comparison UnitTestsSources/FromDcmtkTests.cpp @ 3884:83061cdc7703 transcoding

moving old tests to the graveyard
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 05 May 2020 14:37:29 +0200
parents 795c9ca5eb91
children e23026566536
comparison
equal deleted inserted replaced
3883:795c9ca5eb91 3884:83061cdc7703
1922 1922
1923 1923
1924 1924
1925 #if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 1925 #if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1
1926 1926
1927 #include "../Core/DicomParsing/Internals/DicomFrameIndex.h" 1927 #include "../Core/DicomNetworking/DicomStoreUserConnection.h"
1928 1928
1929 #include <dcmtk/dcmdata/dcostrmb.h>
1930 #include <dcmtk/dcmdata/dcpixel.h>
1931 #include <dcmtk/dcmdata/dcpxitem.h>
1932 #include <dcmtk/dcmjpeg/djrploss.h> // for DJ_RPLossy 1929 #include <dcmtk/dcmjpeg/djrploss.h> // for DJ_RPLossy
1933 #include <dcmtk/dcmjpeg/djrplol.h> // for DJ_RPLossless 1930 #include <dcmtk/dcmjpeg/djrplol.h> // for DJ_RPLossless
1934 1931
1935 1932
1936 #if !defined(ORTHANC_ENABLE_DCMTK_JPEG) 1933 #if !defined(ORTHANC_ENABLE_DCMTK_JPEG)
1939 1936
1940 #if !defined(ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS) 1937 #if !defined(ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS)
1941 # error Macro ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS must be defined 1938 # error Macro ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS must be defined
1942 #endif 1939 #endif
1943 1940
1944
1945
1946 namespace Orthanc
1947 {
1948 class IParsedDicomImage : public boost::noncopyable
1949 {
1950 public:
1951 virtual ~IParsedDicomImage()
1952 {
1953 }
1954
1955 virtual DicomTransferSyntax GetTransferSyntax() = 0;
1956
1957 virtual std::string GetSopClassUid() = 0;
1958
1959 virtual std::string GetSopInstanceUid() = 0;
1960
1961 virtual unsigned int GetFramesCount() = 0;
1962
1963 // Can return NULL, for compressed transfer syntaxes
1964 virtual ImageAccessor* GetUncompressedFrame(unsigned int frame) = 0;
1965
1966 virtual void GetCompressedFrame(std::string& target,
1967 unsigned int frame) = 0;
1968
1969 virtual void WriteToMemoryBuffer(std::string& target) = 0;
1970 };
1971
1972
1973 class IDicomImageReader : public boost::noncopyable
1974 {
1975 public:
1976 virtual ~IDicomImageReader()
1977 {
1978 }
1979
1980 virtual IParsedDicomImage* Read(const void* data,
1981 size_t size) = 0;
1982
1983 virtual IParsedDicomImage* Transcode(const void* data,
1984 size_t size,
1985 DicomTransferSyntax syntax,
1986 bool allowNewSopInstanceUid) = 0;
1987 };
1988
1989
1990 class DcmtkImageReader : public IDicomImageReader
1991 {
1992 private:
1993 class Image : public IParsedDicomImage
1994 {
1995 private:
1996 std::unique_ptr<DcmFileFormat> dicom_;
1997 std::unique_ptr<DicomFrameIndex> index_;
1998 DicomTransferSyntax transferSyntax_;
1999 std::string sopClassUid_;
2000 std::string sopInstanceUid_;
2001
2002 static std::string GetStringTag(DcmDataset& dataset,
2003 const DcmTagKey& tag)
2004 {
2005 const char* value = NULL;
2006
2007 if (!dataset.findAndGetString(tag, value).good() ||
2008 value == NULL)
2009 {
2010 throw OrthancException(ErrorCode_BadFileFormat,
2011 "Missing SOP class/instance UID in DICOM instance");
2012 }
2013 else
2014 {
2015 return std::string(value);
2016 }
2017 }
2018
2019 public:
2020 Image(DcmFileFormat* dicom,
2021 DicomTransferSyntax syntax) :
2022 dicom_(dicom),
2023 transferSyntax_(syntax)
2024 {
2025 if (dicom == NULL ||
2026 dicom_->getDataset() == NULL)
2027 {
2028 throw OrthancException(ErrorCode_NullPointer);
2029 }
2030
2031 DcmDataset& dataset = *dicom_->getDataset();
2032 index_.reset(new DicomFrameIndex(dataset));
2033
2034 sopClassUid_ = GetStringTag(dataset, DCM_SOPClassUID);
2035 sopInstanceUid_ = GetStringTag(dataset, DCM_SOPInstanceUID);
2036 }
2037
2038 virtual DicomTransferSyntax GetTransferSyntax() ORTHANC_OVERRIDE
2039 {
2040 return transferSyntax_;
2041 }
2042
2043 virtual std::string GetSopClassUid() ORTHANC_OVERRIDE
2044 {
2045 return sopClassUid_;
2046 }
2047
2048 virtual std::string GetSopInstanceUid() ORTHANC_OVERRIDE
2049 {
2050 return sopInstanceUid_;
2051 }
2052
2053 virtual unsigned int GetFramesCount() ORTHANC_OVERRIDE
2054 {
2055 return index_->GetFramesCount();
2056 }
2057
2058 virtual void WriteToMemoryBuffer(std::string& target) ORTHANC_OVERRIDE
2059 {
2060 assert(dicom_.get() != NULL);
2061 if (!FromDcmtkBridge::SaveToMemoryBuffer(target, *dicom_, transferSyntax_))
2062 {
2063 throw OrthancException(ErrorCode_InternalError,
2064 "Cannot write the DICOM instance to a memory buffer");
2065 }
2066 }
2067
2068 virtual ImageAccessor* GetUncompressedFrame(unsigned int frame) ORTHANC_OVERRIDE
2069 {
2070 assert(dicom_.get() != NULL &&
2071 dicom_->getDataset() != NULL);
2072 return DicomImageDecoder::Decode(*dicom_->getDataset(), frame);
2073 }
2074
2075 virtual void GetCompressedFrame(std::string& target,
2076 unsigned int frame) ORTHANC_OVERRIDE
2077 {
2078 assert(index_.get() != NULL);
2079 index_->GetRawFrame(target, frame);
2080 }
2081 };
2082
2083 unsigned int lossyQuality_;
2084
2085 static DicomTransferSyntax DetectTransferSyntax(DcmFileFormat& dicom)
2086 {
2087 if (dicom.getDataset() == NULL)
2088 {
2089 throw OrthancException(ErrorCode_InternalError);
2090 }
2091
2092 DcmDataset& dataset = *dicom.getDataset();
2093
2094 E_TransferSyntax xfer = dataset.getCurrentXfer();
2095 if (xfer == EXS_Unknown)
2096 {
2097 dataset.updateOriginalXfer();
2098 xfer = dataset.getCurrentXfer();
2099 if (xfer == EXS_Unknown)
2100 {
2101 throw OrthancException(ErrorCode_BadFileFormat,
2102 "Cannot determine the transfer syntax of the DICOM instance");
2103 }
2104 }
2105
2106 DicomTransferSyntax syntax;
2107 if (FromDcmtkBridge::LookupOrthancTransferSyntax(syntax, xfer))
2108 {
2109 return syntax;
2110 }
2111 else
2112 {
2113 throw OrthancException(
2114 ErrorCode_BadFileFormat,
2115 "Unsupported transfer syntax: " + boost::lexical_cast<std::string>(xfer));
2116 }
2117 }
2118
2119
2120 static uint16_t GetBitsStored(DcmFileFormat& dicom)
2121 {
2122 if (dicom.getDataset() == NULL)
2123 {
2124 throw OrthancException(ErrorCode_InternalError);
2125 }
2126
2127 uint16_t bitsStored;
2128 if (dicom.getDataset()->findAndGetUint16(DCM_BitsStored, bitsStored).good())
2129 {
2130 return bitsStored;
2131 }
2132 else
2133 {
2134 throw OrthancException(ErrorCode_BadFileFormat,
2135 "Missing \"Bits Stored\" tag in DICOM instance");
2136 }
2137 }
2138
2139
2140 public:
2141 DcmtkImageReader() :
2142 lossyQuality_(90)
2143 {
2144 }
2145
2146 void SetLossyQuality(unsigned int quality)
2147 {
2148 if (quality <= 0 ||
2149 quality > 100)
2150 {
2151 throw OrthancException(ErrorCode_ParameterOutOfRange);
2152 }
2153 else
2154 {
2155 lossyQuality_ = quality;
2156 }
2157 }
2158
2159 unsigned int GetLossyQuality() const
2160 {
2161 return lossyQuality_;
2162 }
2163
2164 virtual IParsedDicomImage* Read(const void* data,
2165 size_t size)
2166 {
2167 std::unique_ptr<DcmFileFormat> dicom(FromDcmtkBridge::LoadFromMemoryBuffer(data, size));
2168 if (dicom.get() == NULL)
2169 {
2170 throw OrthancException(ErrorCode_BadFileFormat);
2171 }
2172
2173 DicomTransferSyntax transferSyntax = DetectTransferSyntax(*dicom);
2174
2175 return new Image(dicom.release(), transferSyntax);
2176 }
2177
2178 virtual IParsedDicomImage* Transcode(const void* data,
2179 size_t size,
2180 DicomTransferSyntax syntax,
2181 bool allowNewSopInstanceUid)
2182 {
2183 std::unique_ptr<DcmFileFormat> dicom(FromDcmtkBridge::LoadFromMemoryBuffer(data, size));
2184 if (dicom.get() == NULL)
2185 {
2186 throw OrthancException(ErrorCode_BadFileFormat);
2187 }
2188
2189 const uint16_t bitsStored = GetBitsStored(*dicom);
2190
2191 if (syntax == DetectTransferSyntax(*dicom))
2192 {
2193 // No transcoding is needed
2194 return new Image(dicom.release(), syntax);
2195 }
2196
2197 if (syntax == DicomTransferSyntax_LittleEndianImplicit &&
2198 FromDcmtkBridge::Transcode(*dicom, DicomTransferSyntax_LittleEndianImplicit, NULL))
2199 {
2200 return new Image(dicom.release(), syntax);
2201 }
2202
2203 if (syntax == DicomTransferSyntax_LittleEndianExplicit &&
2204 FromDcmtkBridge::Transcode(*dicom, DicomTransferSyntax_LittleEndianExplicit, NULL))
2205 {
2206 return new Image(dicom.release(), syntax);
2207 }
2208
2209 if (syntax == DicomTransferSyntax_BigEndianExplicit &&
2210 FromDcmtkBridge::Transcode(*dicom, DicomTransferSyntax_BigEndianExplicit, NULL))
2211 {
2212 return new Image(dicom.release(), syntax);
2213 }
2214
2215 if (syntax == DicomTransferSyntax_DeflatedLittleEndianExplicit &&
2216 FromDcmtkBridge::Transcode(*dicom, DicomTransferSyntax_DeflatedLittleEndianExplicit, NULL))
2217 {
2218 return new Image(dicom.release(), syntax);
2219 }
2220
2221 #if ORTHANC_ENABLE_JPEG == 1
2222 if (syntax == DicomTransferSyntax_JPEGProcess1 &&
2223 allowNewSopInstanceUid &&
2224 bitsStored == 8)
2225 {
2226 DJ_RPLossy rpLossy(lossyQuality_);
2227
2228 if (FromDcmtkBridge::Transcode(*dicom, DicomTransferSyntax_JPEGProcess1, &rpLossy))
2229 {
2230 return new Image(dicom.release(), syntax);
2231 }
2232 }
2233 #endif
2234
2235 #if ORTHANC_ENABLE_JPEG == 1
2236 if (syntax == DicomTransferSyntax_JPEGProcess2_4 &&
2237 allowNewSopInstanceUid &&
2238 bitsStored <= 12)
2239 {
2240 DJ_RPLossy rpLossy(lossyQuality_);
2241 if (FromDcmtkBridge::Transcode(*dicom, DicomTransferSyntax_JPEGProcess2_4, &rpLossy))
2242 {
2243 return new Image(dicom.release(), syntax);
2244 }
2245 }
2246 #endif
2247
2248 //LOG(INFO) << "Unable to transcode DICOM image using the built-in reader";
2249 return NULL;
2250 }
2251 };
2252
2253
2254
2255 class IDicomTranscoder1 : public boost::noncopyable
2256 {
2257 public:
2258 virtual ~IDicomTranscoder1()
2259 {
2260 }
2261
2262 virtual DcmFileFormat& GetDicom() = 0;
2263
2264 virtual DicomTransferSyntax GetTransferSyntax() = 0;
2265
2266 virtual std::string GetSopClassUid() = 0;
2267
2268 virtual std::string GetSopInstanceUid() = 0;
2269
2270 virtual unsigned int GetFramesCount() = 0;
2271
2272 virtual ImageAccessor* DecodeFrame(unsigned int frame) = 0;
2273
2274 virtual void GetCompressedFrame(std::string& target,
2275 unsigned int frame) = 0;
2276
2277 // NB: Transcoding can change the value of "GetSopInstanceUid()"
2278 // and "GetTransferSyntax()" if lossy compression is applied
2279 virtual bool Transcode(std::string& target,
2280 DicomTransferSyntax syntax,
2281 bool allowNewSopInstanceUid) = 0;
2282
2283 virtual void WriteToMemoryBuffer(std::string& target) = 0;
2284 };
2285
2286
2287 class DcmtkTranscoder2 : public IDicomTranscoder1
2288 {
2289 private:
2290 std::unique_ptr<DcmFileFormat> dicom_;
2291 std::unique_ptr<DicomFrameIndex> index_;
2292 DicomTransferSyntax transferSyntax_;
2293 std::string sopClassUid_;
2294 std::string sopInstanceUid_;
2295 uint16_t bitsStored_;
2296 unsigned int lossyQuality_;
2297
2298 static std::string GetStringTag(DcmDataset& dataset,
2299 const DcmTagKey& tag)
2300 {
2301 const char* value = NULL;
2302
2303 if (!dataset.findAndGetString(tag, value).good() ||
2304 value == NULL)
2305 {
2306 throw OrthancException(ErrorCode_BadFileFormat,
2307 "Missing SOP class/instance UID in DICOM instance");
2308 }
2309 else
2310 {
2311 return std::string(value);
2312 }
2313 }
2314
2315 void Setup(DcmFileFormat* dicom)
2316 {
2317 lossyQuality_ = 90;
2318
2319 dicom_.reset(dicom);
2320
2321 if (dicom == NULL ||
2322 dicom_->getDataset() == NULL)
2323 {
2324 throw OrthancException(ErrorCode_NullPointer);
2325 }
2326
2327 DcmDataset& dataset = *dicom_->getDataset();
2328 index_.reset(new DicomFrameIndex(dataset));
2329
2330 E_TransferSyntax xfer = dataset.getCurrentXfer();
2331 if (xfer == EXS_Unknown)
2332 {
2333 dataset.updateOriginalXfer();
2334 xfer = dataset.getCurrentXfer();
2335 if (xfer == EXS_Unknown)
2336 {
2337 throw OrthancException(ErrorCode_BadFileFormat,
2338 "Cannot determine the transfer syntax of the DICOM instance");
2339 }
2340 }
2341
2342 if (!FromDcmtkBridge::LookupOrthancTransferSyntax(transferSyntax_, xfer))
2343 {
2344 throw OrthancException(
2345 ErrorCode_BadFileFormat,
2346 "Unsupported transfer syntax: " + boost::lexical_cast<std::string>(xfer));
2347 }
2348
2349 if (!dataset.findAndGetUint16(DCM_BitsStored, bitsStored_).good())
2350 {
2351 throw OrthancException(ErrorCode_BadFileFormat,
2352 "Missing \"Bits Stored\" tag in DICOM instance");
2353 }
2354
2355 sopClassUid_ = GetStringTag(dataset, DCM_SOPClassUID);
2356 sopInstanceUid_ = GetStringTag(dataset, DCM_SOPInstanceUID);
2357 }
2358
2359 public:
2360 DcmtkTranscoder2(DcmFileFormat* dicom) // Takes ownership
2361 {
2362 Setup(dicom);
2363 }
2364
2365 DcmtkTranscoder2(const void* dicom,
2366 size_t size)
2367 {
2368 Setup(FromDcmtkBridge::LoadFromMemoryBuffer(dicom, size));
2369 }
2370
2371 void SetLossyQuality(unsigned int quality)
2372 {
2373 if (quality <= 0 ||
2374 quality > 100)
2375 {
2376 throw OrthancException(ErrorCode_ParameterOutOfRange);
2377 }
2378 else
2379 {
2380 lossyQuality_ = quality;
2381 }
2382 }
2383
2384 unsigned int GetLossyQuality() const
2385 {
2386 return lossyQuality_;
2387 }
2388
2389 unsigned int GetBitsStored() const
2390 {
2391 return bitsStored_;
2392 }
2393
2394 virtual DcmFileFormat& GetDicom()
2395 {
2396 assert(dicom_ != NULL);
2397 return *dicom_;
2398 }
2399
2400 virtual DicomTransferSyntax GetTransferSyntax() ORTHANC_OVERRIDE
2401 {
2402 return transferSyntax_;
2403 }
2404
2405 virtual std::string GetSopClassUid() ORTHANC_OVERRIDE
2406 {
2407 return sopClassUid_;
2408 }
2409
2410 virtual std::string GetSopInstanceUid() ORTHANC_OVERRIDE
2411 {
2412 return sopInstanceUid_;
2413 }
2414
2415 virtual unsigned int GetFramesCount() ORTHANC_OVERRIDE
2416 {
2417 return index_->GetFramesCount();
2418 }
2419
2420 virtual void WriteToMemoryBuffer(std::string& target) ORTHANC_OVERRIDE
2421 {
2422 if (!FromDcmtkBridge::SaveToMemoryBuffer(target, *dicom_))
2423 {
2424 throw OrthancException(ErrorCode_InternalError,
2425 "Cannot write the DICOM instance to a memory buffer");
2426 }
2427 }
2428
2429 virtual ImageAccessor* DecodeFrame(unsigned int frame) ORTHANC_OVERRIDE
2430 {
2431 assert(dicom_->getDataset() != NULL);
2432 return DicomImageDecoder::Decode(*dicom_->getDataset(), frame);
2433 }
2434
2435 virtual void GetCompressedFrame(std::string& target,
2436 unsigned int frame) ORTHANC_OVERRIDE
2437 {
2438 index_->GetRawFrame(target, frame);
2439 }
2440
2441 virtual bool Transcode(std::string& target,
2442 DicomTransferSyntax syntax,
2443 bool allowNewSopInstanceUid) ORTHANC_OVERRIDE
2444 {
2445 assert(dicom_ != NULL &&
2446 dicom_->getDataset() != NULL);
2447
2448 if (syntax == GetTransferSyntax())
2449 {
2450 printf("NO TRANSCODING\n");
2451
2452 // No change in the transfer syntax => simply serialize the current dataset
2453 WriteToMemoryBuffer(target);
2454 return true;
2455 }
2456
2457 printf(">> %d\n", bitsStored_);
2458
2459 if (syntax == DicomTransferSyntax_LittleEndianImplicit &&
2460 FromDcmtkBridge::Transcode(*dicom_, syntax, NULL) &&
2461 FromDcmtkBridge::SaveToMemoryBuffer(target, *dicom_, syntax))
2462 {
2463 transferSyntax_ = DicomTransferSyntax_LittleEndianImplicit;
2464 return true;
2465 }
2466
2467 if (syntax == DicomTransferSyntax_LittleEndianExplicit &&
2468 FromDcmtkBridge::Transcode(*dicom_, syntax, NULL) &&
2469 FromDcmtkBridge::SaveToMemoryBuffer(target, *dicom_, syntax))
2470 {
2471 transferSyntax_ = DicomTransferSyntax_LittleEndianExplicit;
2472 return true;
2473 }
2474
2475 if (syntax == DicomTransferSyntax_BigEndianExplicit &&
2476 FromDcmtkBridge::Transcode(*dicom_, syntax, NULL) &&
2477 FromDcmtkBridge::SaveToMemoryBuffer(target, *dicom_, syntax))
2478 {
2479 transferSyntax_ = DicomTransferSyntax_BigEndianExplicit;
2480 return true;
2481 }
2482
2483 if (syntax == DicomTransferSyntax_DeflatedLittleEndianExplicit &&
2484 FromDcmtkBridge::Transcode(*dicom_, syntax, NULL) &&
2485 FromDcmtkBridge::SaveToMemoryBuffer(target, *dicom_, syntax))
2486 {
2487 transferSyntax_ = DicomTransferSyntax_DeflatedLittleEndianExplicit;
2488 return true;
2489 }
2490
2491 #if ORTHANC_ENABLE_JPEG == 1
2492 if (syntax == DicomTransferSyntax_JPEGProcess1 &&
2493 allowNewSopInstanceUid &&
2494 GetBitsStored() == 8)
2495 {
2496 DJ_RPLossy rpLossy(lossyQuality_);
2497
2498 if (FromDcmtkBridge::Transcode(*dicom_, syntax, &rpLossy) &&
2499 FromDcmtkBridge::SaveToMemoryBuffer(target, *dicom_, syntax))
2500 {
2501 transferSyntax_ = DicomTransferSyntax_JPEGProcess1;
2502 sopInstanceUid_ = GetStringTag(*dicom_->getDataset(), DCM_SOPInstanceUID);
2503 return true;
2504 }
2505 }
2506 #endif
2507
2508 #if ORTHANC_ENABLE_JPEG == 1
2509 if (syntax == DicomTransferSyntax_JPEGProcess2_4 &&
2510 allowNewSopInstanceUid &&
2511 GetBitsStored() <= 12)
2512 {
2513 DJ_RPLossy rpLossy(lossyQuality_);
2514 if (FromDcmtkBridge::Transcode(*dicom_, syntax, &rpLossy) &&
2515 FromDcmtkBridge::SaveToMemoryBuffer(target, *dicom_, syntax))
2516 {
2517 transferSyntax_ = DicomTransferSyntax_JPEGProcess2_4;
2518 sopInstanceUid_ = GetStringTag(*dicom_->getDataset(), DCM_SOPInstanceUID);
2519 return true;
2520 }
2521 }
2522 #endif
2523
2524 return false;
2525 }
2526 };
2527 }
2528
2529
2530
2531
2532 #include <boost/filesystem.hpp>
2533
2534
2535 static void TestFile(const std::string& path)
2536 {
2537 static unsigned int count = 0;
2538 count++;
2539
2540
2541 printf("** %s\n", path.c_str());
2542
2543 std::string s;
2544 SystemToolbox::ReadFile(s, path);
2545
2546 Orthanc::DcmtkTranscoder2 transcoder(s.c_str(), s.size());
2547
2548 /*if (transcoder.GetBitsStored() != 8) // TODO
2549 return; */
2550
2551 {
2552 char buf[1024];
2553 sprintf(buf, "/tmp/source-%06d.dcm", count);
2554 printf(">> %s\n", buf);
2555 Orthanc::SystemToolbox::WriteFile(s, buf);
2556 }
2557
2558 printf("[%s] [%s] [%s] %d %d\n", GetTransferSyntaxUid(transcoder.GetTransferSyntax()),
2559 transcoder.GetSopClassUid().c_str(), transcoder.GetSopInstanceUid().c_str(),
2560 transcoder.GetFramesCount(), transcoder.GetTransferSyntax());
2561
2562 for (size_t i = 0; i < transcoder.GetFramesCount(); i++)
2563 {
2564 std::string f;
2565 transcoder.GetCompressedFrame(f, i);
2566
2567 if (i == 0)
2568 {
2569 char buf[1024];
2570 sprintf(buf, "/tmp/frame-%06d.raw", count);
2571 printf(">> %s\n", buf);
2572 Orthanc::SystemToolbox::WriteFile(f, buf);
2573 }
2574 }
2575
2576 {
2577 std::string t;
2578 transcoder.WriteToMemoryBuffer(t);
2579
2580 Orthanc::DcmtkTranscoder2 transcoder2(t.c_str(), t.size());
2581 printf(">> %d %d ; %lu bytes\n", transcoder.GetTransferSyntax(), transcoder2.GetTransferSyntax(), t.size());
2582 }
2583
2584 {
2585 std::string a = transcoder.GetSopInstanceUid();
2586 DicomTransferSyntax b = transcoder.GetTransferSyntax();
2587
2588 DicomTransferSyntax syntax = DicomTransferSyntax_JPEGProcess2_4;
2589 //DicomTransferSyntax syntax = DicomTransferSyntax_LittleEndianExplicit;
2590
2591 std::string t;
2592 bool ok = transcoder.Transcode(t, syntax, true);
2593 printf("Transcoding: %d\n", ok);
2594
2595 if (ok)
2596 {
2597 printf("[%s] => [%s]\n", a.c_str(), transcoder.GetSopInstanceUid().c_str());
2598 printf("[%s] => [%s]\n", GetTransferSyntaxUid(b),
2599 GetTransferSyntaxUid(transcoder.GetTransferSyntax()));
2600
2601 {
2602 char buf[1024];
2603 sprintf(buf, "/tmp/transcoded-%06d.dcm", count);
2604 printf(">> %s\n", buf);
2605 Orthanc::SystemToolbox::WriteFile(t, buf);
2606 }
2607
2608 Orthanc::DcmtkTranscoder2 transcoder2(t.c_str(), t.size());
2609 printf(" => transcoded transfer syntax %d ; %lu bytes\n", transcoder2.GetTransferSyntax(), t.size());
2610 }
2611 }
2612
2613 printf("\n");
2614 }
2615
2616 TEST(Toto, DISABLED_Transcode)
2617 {
2618 //OFLog::configure(OFLogger::DEBUG_LOG_LEVEL);
2619
2620 if (1)
2621 {
2622 const char* const PATH = "/home/jodogne/Subversion/orthanc-tests/Database/TransferSyntaxes";
2623
2624 for (boost::filesystem::directory_iterator it(PATH);
2625 it != boost::filesystem::directory_iterator(); ++it)
2626 {
2627 if (boost::filesystem::is_regular_file(it->status()))
2628 {
2629 TestFile(it->path().string());
2630 }
2631 }
2632 }
2633
2634 if (0)
2635 {
2636 TestFile("/home/jodogne/Subversion/orthanc-tests/Database/Multiframe.dcm");
2637 TestFile("/home/jodogne/Subversion/orthanc-tests/Database/Issue44/Monochrome1-Jpeg.dcm");
2638 }
2639
2640 if (0)
2641 {
2642 TestFile("/home/jodogne/Subversion/orthanc-tests/Database/TransferSyntaxes/1.2.840.10008.1.2.1.dcm");
2643 }
2644 }
2645
2646
2647 TEST(Toto, DISABLED_Transcode2)
2648 {
2649 for (int i = 0; i <= DicomTransferSyntax_XML; i++)
2650 {
2651 DicomTransferSyntax a = (DicomTransferSyntax) i;
2652
2653 std::string path = ("/home/jodogne/Subversion/orthanc-tests/Database/TransferSyntaxes/" +
2654 std::string(GetTransferSyntaxUid(a)) + ".dcm");
2655 if (Orthanc::SystemToolbox::IsRegularFile(path))
2656 {
2657 printf("\n======= %s\n", GetTransferSyntaxUid(a));
2658
2659 std::string source;
2660 Orthanc::SystemToolbox::ReadFile(source, path);
2661
2662 DcmtkImageReader reader;
2663
2664 {
2665 std::unique_ptr<IParsedDicomImage> image(
2666 reader.Read(source.c_str(), source.size()));
2667 ASSERT_TRUE(image.get() != NULL);
2668 ASSERT_EQ(a, image->GetTransferSyntax());
2669
2670 std::string target;
2671 image->WriteToMemoryBuffer(target);
2672 }
2673
2674 for (int j = 0; j <= DicomTransferSyntax_XML; j++)
2675 {
2676 DicomTransferSyntax b = (DicomTransferSyntax) j;
2677 //if (a == b) continue;
2678
2679 std::unique_ptr<IParsedDicomImage> image(
2680 reader.Transcode(source.c_str(), source.size(), b, true));
2681 if (image.get() != NULL)
2682 {
2683 printf("[%s] -> [%s]\n", GetTransferSyntaxUid(a), GetTransferSyntaxUid(b));
2684
2685 std::string target;
2686 image->WriteToMemoryBuffer(target);
2687
2688 char buf[1024];
2689 sprintf(buf, "/tmp/%s-%s.dcm", GetTransferSyntaxUid(a), GetTransferSyntaxUid(b));
2690
2691 SystemToolbox::WriteFile(target, buf);
2692 }
2693 else if (a != DicomTransferSyntax_JPEG2000 &&
2694 a != DicomTransferSyntax_JPEG2000LosslessOnly)
2695 {
2696 ASSERT_TRUE(b != DicomTransferSyntax_LittleEndianImplicit &&
2697 b != DicomTransferSyntax_LittleEndianExplicit &&
2698 b != DicomTransferSyntax_BigEndianExplicit &&
2699 b != DicomTransferSyntax_DeflatedLittleEndianExplicit);
2700 }
2701 }
2702 }
2703 }
2704 }
2705
2706
2707 #include "../Core/DicomNetworking/DicomAssociation.h"
2708 #include "../Core/DicomNetworking/DicomControlUserConnection.h"
2709 #include "../Core/DicomNetworking/DicomStoreUserConnection.h"
2710
2711 TEST(Toto, DISABLED_DicomAssociation)
2712 {
2713 DicomAssociationParameters params;
2714 params.SetLocalApplicationEntityTitle("ORTHANC");
2715 params.SetRemoteApplicationEntityTitle("PACS");
2716 params.SetRemotePort(2001);
2717
2718 #if 0
2719 DicomAssociation assoc;
2720 assoc.ProposeGenericPresentationContext(UID_StorageCommitmentPushModelSOPClass);
2721 assoc.ProposeGenericPresentationContext(UID_VerificationSOPClass);
2722 assoc.ProposePresentationContext(UID_ComputedRadiographyImageStorage,
2723 DicomTransferSyntax_JPEGProcess1);
2724 assoc.ProposePresentationContext(UID_ComputedRadiographyImageStorage,
2725 DicomTransferSyntax_JPEGProcess2_4);
2726 assoc.ProposePresentationContext(UID_ComputedRadiographyImageStorage,
2727 DicomTransferSyntax_JPEG2000);
2728
2729 assoc.Open(params);
2730
2731 int presID = ASC_findAcceptedPresentationContextID(&assoc.GetDcmtkAssociation(), UID_ComputedRadiographyImageStorage);
2732 printf(">> %d\n", presID);
2733
2734 std::map<DicomTransferSyntax, uint8_t> pc;
2735 printf(">> %d\n", assoc.LookupAcceptedPresentationContext(pc, UID_ComputedRadiographyImageStorage));
2736
2737 for (std::map<DicomTransferSyntax, uint8_t>::const_iterator
2738 it = pc.begin(); it != pc.end(); ++it)
2739 {
2740 printf("[%s] => %d\n", GetTransferSyntaxUid(it->first), it->second);
2741 }
2742 #else
2743 {
2744 DicomControlUserConnection assoc(params);
2745
2746 try
2747 {
2748 printf(">> %d\n", assoc.Echo());
2749 }
2750 catch (OrthancException&)
2751 {
2752 }
2753 }
2754
2755 params.SetRemoteApplicationEntityTitle("PACS");
2756 params.SetRemotePort(2000);
2757
2758 {
2759 DicomControlUserConnection assoc(params);
2760 printf(">> %d\n", assoc.Echo());
2761 }
2762
2763 #endif
2764 }
2765
2766 static void TestTranscode(DicomStoreUserConnection& scu,
2767 const std::string& sopClassUid,
2768 DicomTransferSyntax transferSyntax)
2769 {
2770 std::set<DicomTransferSyntax> accepted;
2771
2772 scu.LookupTranscoding(accepted, sopClassUid, transferSyntax);
2773 if (accepted.empty())
2774 {
2775 throw OrthancException(ErrorCode_NetworkProtocol,
2776 "The SOP class is not supported by the remote modality");
2777 }
2778
2779 {
2780 unsigned int count = 0;
2781 for (std::set<DicomTransferSyntax>::const_iterator
2782 it = accepted.begin(); it != accepted.end(); ++it)
2783 {
2784 LOG(INFO) << "available for transcoding " << (count++) << ": " << sopClassUid
2785 << " / " << GetTransferSyntaxUid(*it);
2786 }
2787 }
2788
2789 if (accepted.find(transferSyntax) != accepted.end())
2790 {
2791 printf("**** OK, without transcoding !! [%s]\n", GetTransferSyntaxUid(transferSyntax));
2792 }
2793 else
2794 {
2795 // Transcoding - only in Orthanc >= 1.7.0
2796
2797 const DicomTransferSyntax uncompressed[] = {
2798 DicomTransferSyntax_LittleEndianImplicit, // Default transfer syntax
2799 DicomTransferSyntax_LittleEndianExplicit,
2800 DicomTransferSyntax_BigEndianExplicit
2801 };
2802
2803 bool found = false;
2804 for (size_t i = 0; i < 3; i++)
2805 {
2806 if (accepted.find(uncompressed[i]) != accepted.end())
2807 {
2808 printf("**** TRANSCODING to %s\n", GetTransferSyntaxUid(uncompressed[i]));
2809 found = true;
2810 break;
2811 }
2812 }
2813
2814 if (!found)
2815 {
2816 printf("**** KO KO KO\n");
2817 }
2818 }
2819 }
2820
2821
2822 TEST(Toto, DISABLED_Store)
2823 {
2824 DicomAssociationParameters params;
2825 params.SetLocalApplicationEntityTitle("ORTHANC");
2826 params.SetRemoteApplicationEntityTitle("STORESCP");
2827 params.SetRemotePort(2000);
2828
2829 DicomStoreUserConnection assoc(params);
2830 assoc.RegisterStorageClass(UID_MRImageStorage, DicomTransferSyntax_JPEGProcess1);
2831 assoc.RegisterStorageClass(UID_MRImageStorage, DicomTransferSyntax_JPEGProcess2_4);
2832 //assoc.RegisterStorageClass(UID_MRImageStorage, DicomTransferSyntax_LittleEndianExplicit);
2833
2834 //assoc.SetUncompressedSyntaxesProposed(false); // Necessary for transcoding
2835 assoc.SetCommonClassesProposed(false);
2836 assoc.SetRetiredBigEndianProposed(true);
2837 TestTranscode(assoc, UID_MRImageStorage, DicomTransferSyntax_LittleEndianExplicit);
2838 TestTranscode(assoc, UID_MRImageStorage, DicomTransferSyntax_JPEG2000);
2839 TestTranscode(assoc, UID_MRImageStorage, DicomTransferSyntax_JPEG2000);
2840 }
2841
2842
2843 TEST(Toto, DISABLED_Store2)
2844 {
2845 DicomAssociationParameters params;
2846 params.SetLocalApplicationEntityTitle("ORTHANC");
2847 params.SetRemoteApplicationEntityTitle("STORESCP");
2848 params.SetRemotePort(2000);
2849
2850 DicomStoreUserConnection assoc(params);
2851 //assoc.SetCommonClassesProposed(false);
2852 assoc.SetRetiredBigEndianProposed(true);
2853
2854 std::string s;
2855 Orthanc::SystemToolbox::ReadFile(s, "/tmp/i/" + std::string(GetTransferSyntaxUid(DicomTransferSyntax_BigEndianExplicit)) +".dcm");
2856
2857 std::string c, i;
2858 assoc.Store(c, i, s.c_str(), s.size());
2859 printf("[%s] [%s]\n", c.c_str(), i.c_str());
2860 }
2861 1941
2862 1942
2863 namespace Orthanc 1943 namespace Orthanc
2864 { 1944 {
2865 class IDicomTranscoder : public boost::noncopyable 1945 class IDicomTranscoder : public boost::noncopyable
3165 DicomStoreUserConnection scu(p); 2245 DicomStoreUserConnection scu(p);
3166 scu.SetCommonClassesProposed(false); 2246 scu.SetCommonClassesProposed(false);
3167 scu.SetRetiredBigEndianProposed(true); 2247 scu.SetRetiredBigEndianProposed(true);
3168 2248
3169 std::string c, i; 2249 std::string c, i;
3170 IDicomTranscoder::Store(c, i, scu, transcoder, source.c_str(), source.size()); 2250 try
2251 {
2252 IDicomTranscoder::Store(c, i, scu, transcoder, source.c_str(), source.size());
2253 }
2254 catch (OrthancException& e)
2255 {
2256 if (e.GetErrorCode() == ErrorCode_NotImplemented)
2257 {
2258 LOG(ERROR) << "cannot transcode " << GetTransferSyntaxUid(a);
2259 }
2260 else
2261 {
2262 throw e;
2263 }
2264 }
3171 } 2265 }
3172 } 2266 }
3173 } 2267 }
3174 2268
3175 2269