New upstream version 2.8.9
Gert Wollny
5 years ago
50 | 50 | reader.SetFileName( filename ); |
51 | 51 | if( !reader.Read() ) |
52 | 52 | { |
53 | std::cerr << "Could not read : " << filename << std::endl; | |
53 | std::cerr << "Could not read : " << filename; | |
54 | 54 | if( continuemode ) |
55 | 55 | { |
56 | std::cerr << "Skipping from anonymization process (continue mode)." << std::endl; | |
56 | std::cerr << " -> Skipping from anonymization process (continue mode)." << std::endl; | |
57 | 57 | return true; |
58 | 58 | } |
59 | 59 | else |
60 | 60 | { |
61 | std::cerr << "Check [--continue] option for skipping files." << std::endl; | |
61 | std::cerr << " -> Check [--continue] option for skipping files." << std::endl; | |
62 | 62 | return false; |
63 | 63 | } |
64 | 64 | } |
610 | 610 | crypto_factory = gdcm::CryptoFactory::GetFactoryInstance(crypto_lib); |
611 | 611 | if (!crypto_factory) |
612 | 612 | { |
613 | std::cerr << "Requested cryptoraphic library not configured." << std::endl; | |
613 | std::cerr << "Requested cryptographic library not configured." << std::endl; | |
614 | 614 | return 1; |
615 | 615 | } |
616 | 616 | } |
69 | 69 | #include <getopt.h> |
70 | 70 | #include <string.h> |
71 | 71 | |
72 | #ifndef GDCM_HAVE_ATOLL | |
72 | 73 | #ifdef _MSC_VER |
73 | 74 | #define atoll _atoi64 |
75 | #else | |
76 | #define atoll atol | |
77 | #endif | |
74 | 78 | #endif |
75 | 79 | |
76 | 80 | static unsigned int readsize(const char *str, unsigned int * size) |
966 | 970 | |
967 | 971 | if( gdcm::System::StrCaseCmp(inputextension,".pgm") == 0 |
968 | 972 | || gdcm::System::StrCaseCmp(inputextension,".pnm") == 0 |
973 | || gdcm::System::StrCaseCmp(inputextension,".pbm") == 0 | |
969 | 974 | || gdcm::System::StrCaseCmp(inputextension,".ppm") == 0 ) |
970 | 975 | { |
971 | 976 | gdcm::PNMCodec pnm; |
1113 | 1118 | { |
1114 | 1119 | if( gdcm::System::StrCaseCmp(outputextension,".pgm") == 0 |
1115 | 1120 | || gdcm::System::StrCaseCmp(outputextension,".pnm") == 0 |
1121 | || gdcm::System::StrCaseCmp(outputextension,".pbm") == 0 | |
1116 | 1122 | || gdcm::System::StrCaseCmp(outputextension,".ppm") == 0 ) |
1117 | 1123 | { |
1118 | 1124 | gdcm::PNMCodec pnm; |
257 | 257 | { |
258 | 258 | Object obj; |
259 | 259 | const GooString *s1; |
260 | GBool isUnicode; | |
260 | bool isUnicode; | |
261 | 261 | Unicode u; |
262 | 262 | char buf[8]; |
263 | 263 | int i, n; |
273 | 273 | if ((s1->getChar(0) & 0xff) == 0xfe && |
274 | 274 | (s1->getChar(1) & 0xff) == 0xff) |
275 | 275 | { |
276 | isUnicode = gTrue; | |
276 | isUnicode = true; | |
277 | 277 | i = 2; |
278 | 278 | } |
279 | 279 | else |
280 | 280 | { |
281 | isUnicode = gFalse; | |
281 | isUnicode = false; | |
282 | 282 | i = 0; |
283 | 283 | } |
284 | 284 | while (i < obj.getString()->getLength()) |
538 | 538 | int pages = doc->getNumPages(); |
539 | 539 | const char *encrypted = doc->isEncrypted() ? "yes" : "no"; |
540 | 540 | // printf("yes (print:%s copy:%s change:%s addNotes:%s)\n", |
541 | // doc->okToPrint(gTrue) ? "yes" : "no", | |
542 | // doc->okToCopy(gTrue) ? "yes" : "no", | |
543 | // doc->okToChange(gTrue) ? "yes" : "no", | |
544 | // doc->okToAddNotes(gTrue) ? "yes" : "no"); | |
541 | // doc->okToPrint(true) ? "yes" : "no", | |
542 | // doc->okToCopy(true) ? "yes" : "no", | |
543 | // doc->okToChange(true) ? "yes" : "no", | |
544 | // doc->okToAddNotes(true) ? "yes" : "no"); | |
545 | 545 | |
546 | 546 | // print linearization info |
547 | 547 | const char *optimized = doc->isLinearized() ? "yes" : "no"; |
101 | 101 | return out; |
102 | 102 | } |
103 | 103 | |
104 | static std::string getInfoString(Dict *infoDict, const char *key, UnicodeMap *uMap, GBool & unicode) | |
104 | static std::string getInfoString(Dict *infoDict, const char *key, UnicodeMap *uMap, bool & unicode) | |
105 | 105 | { |
106 | 106 | Object obj; |
107 | 107 | const GooString *s1; |
108 | GBool isUnicode = gFalse; | |
108 | bool isUnicode = false; | |
109 | 109 | Unicode u; |
110 | 110 | char buf[8]; |
111 | 111 | int i, n; |
121 | 121 | if ((s1->getChar(0) & 0xff) == 0xfe && |
122 | 122 | (s1->getChar(1) & 0xff) == 0xff) |
123 | 123 | { |
124 | isUnicode = gTrue; | |
124 | isUnicode = true; | |
125 | 125 | i = 2; |
126 | 126 | } |
127 | 127 | else |
128 | 128 | { |
129 | isUnicode = gFalse; | |
129 | isUnicode = false; | |
130 | 130 | i = 0; |
131 | 131 | } |
132 | 132 | while (i < obj.getString()->getLength()) |
397 | 397 | std::string creationdate; |
398 | 398 | std::string moddate; |
399 | 399 | |
400 | GBool isUnicode = gFalse; | |
400 | bool isUnicode = false; | |
401 | 401 | if (doc->isOk()) |
402 | 402 | { |
403 | 403 | #ifdef LIBPOPPLER_NEW_OBJECT_API |
522 | 522 | // construct the target name: |
523 | 523 | std::string targetname = targetdir; |
524 | 524 | |
525 | targetdir += "/old/"; | |
525 | targetdir += "/old"; | |
526 | 526 | |
527 | 527 | // make sure the dir exist first: |
528 | 528 | if( !gdcm::System::MakeDirectory( targetdir.c_str() ) ) |
778 | 778 | if( !unsorted.empty() ) |
779 | 779 | { |
780 | 780 | std::string targetdir3 = outfilename; |
781 | targetdir3 += "/unhandled/"; | |
781 | targetdir3 += "/unhandled"; | |
782 | 782 | if( !gdcm::System::MakeDirectory( targetdir3.c_str() ) ) |
783 | 783 | { |
784 | std::cerr << "Could not create dir: " << outfilename << std::endl; | |
784 | std::cerr << "Could not create dir: " << targetdir3 << std::endl; | |
785 | 785 | return 1; |
786 | 786 | } |
787 | 787 | std::cerr << "Could not process the following files (please report): " << std::endl; |
42 | 42 | #---------------------------------------------------------------------------- |
43 | 43 | set(GDCM_MAJOR_VERSION 2) |
44 | 44 | set(GDCM_MINOR_VERSION 8) |
45 | set(GDCM_BUILD_VERSION 8) | |
45 | set(GDCM_BUILD_VERSION 9) | |
46 | 46 | set(GDCM_VERSION |
47 | 47 | "${GDCM_MAJOR_VERSION}.${GDCM_MINOR_VERSION}.${GDCM_BUILD_VERSION}") |
48 | 48 | # let advanced user the option to define GDCM_API_VERSION: |
50 | 50 | set(CMAKE_REQUIRED_INCLUDES math.h) |
51 | 51 | set(CMAKE_REQUIRED_LIBRARIES m) |
52 | 52 | check_function_exists(lround GDCM_HAVE_LROUND) |
53 | set(CMAKE_REQUIRED_INCLUDES stdlib.h) | |
54 | check_function_exists(atoll GDCM_HAVE_ATOLL) | |
55 | unset(CMAKE_REQUIRED_INCLUDES) | |
56 | unset(CMAKE_REQUIRED_LIBRARIES) | |
53 | 57 | |
54 | 58 | #include(CheckSymbolExists) |
55 | 59 | CHECK_FUNCTION_EXISTS(gettimeofday GDCM_HAVE_GETTIMEOFDAY) |
116 | 116 | #cmakedefine GDCM_HAVE__SNPRINTF |
117 | 117 | #cmakedefine GDCM_HAVE_LROUND |
118 | 118 | #cmakedefine GDCM_HAVE_GETTIMEOFDAY |
119 | #cmakedefine GDCM_HAVE_ATOLL | |
119 | 120 | #cmakedefine GDCM_HAVE_JSON_OBJECT_OBJECT_GET_EX |
120 | 121 | |
121 | 122 | // MM: I have a feeling that if GDCM_HAVE_WCHAR_IFSTREAM, then UNICODE filename |
157 | 157 | bool ok = true; |
158 | 158 | while(ok && (pos = dir.find('/', pos)) != std::string::npos) |
159 | 159 | { |
160 | topdir = dir.substr(0, pos); | |
161 | ok = ok && Mkdir(topdir.c_str()); | |
160 | topdir = dir.substr(0, pos+1); | |
161 | ok = ok && (System::FileIsDirectory(topdir.c_str()) || 0 == Mkdir(topdir.c_str())); | |
162 | 162 | pos++; |
163 | 163 | } |
164 | 164 | if( !ok ) return false; |
23 | 23 | #include "gdcmDict.h" |
24 | 24 | #include "gdcmDictEntry.h" |
25 | 25 | |
26 | namespace gdcm { | |
26 | namespace { | |
27 | using namespace gdcm; | |
27 | 28 | typedef struct |
28 | 29 | { |
29 | 30 | uint16_t group; |
13274 | 13275 | {0xffff,0xffff,VR::INVALID,VM::VM0,"","",true }, // dummy |
13275 | 13276 | {0xffff,0xffff,VR::INVALID,VM::VM0,0,0,true } // Gard |
13276 | 13277 | }; |
13278 | } // end anonymous namespace | |
13279 | ||
13280 | namespace gdcm { | |
13277 | 13281 | |
13278 | 13282 | void Dict::LoadDefault() |
13279 | 13283 | { |
23 | 23 | #include "gdcmDict.h" |
24 | 24 | #include "gdcmDictEntry.h" |
25 | 25 | |
26 | namespace gdcm { | |
26 | namespace { | |
27 | using namespace gdcm; | |
27 | 28 | typedef struct |
28 | 29 | { |
29 | 30 | uint16_t group; |
10262 | 10263 | {0xffff,0xffff,"GDCM Private Sentinel",VR::INVALID,VM::VM0,"",true }, // Dummy invalid element |
10263 | 10264 | {0xffff,0xffff,"",VR::INVALID,VM::VM0,0,true } // Gard (will NOT be added) |
10264 | 10265 | }; |
10266 | } //end anonymous namespace | |
10267 | namespace gdcm { | |
10265 | 10268 | |
10266 | 10269 | /* |
10267 | 10270 | void Dict::LoadDefault() |
53 | 53 | if( TagField != itemStart ) |
54 | 54 | { |
55 | 55 | // Bug_Siemens_PrivateIconNoItem.dcm |
56 | gdcmDebugMacro( "Could be Bug_Siemens_PrivateIconNoItem.dcm" ); | |
57 | throw "SIEMENS Icon thingy"; | |
56 | //gdcmDebugMacro( "Could be Bug_Siemens_PrivateIconNoItem.dcm" ); | |
57 | ParseException pe; | |
58 | pe.SetLastElement(*this); | |
59 | //throw "SIEMENS Icon thingy"; | |
60 | throw pe; | |
58 | 61 | } |
59 | 62 | if( !ValueLengthField.Read<TSwap>(is) ) |
60 | 63 | { |
92 | 92 | template <typename TSwap> |
93 | 93 | std::istream& ReadPreValue(std::istream &is) |
94 | 94 | { |
95 | //if( SequenceLengthField.IsUndefined() ) | |
96 | 95 | // First item is the basic offset table: |
96 | #if 0 | |
97 | 97 | try |
98 | 98 | { |
99 | 99 | Table.Read<TSwap>(is); |
124 | 124 | //assert(0); |
125 | 125 | } |
126 | 126 | } |
127 | #else | |
128 | Table.Read<TSwap>(is); | |
129 | gdcmDebugMacro( "Table: " << Table ); | |
130 | #endif | |
127 | 131 | return is; |
128 | 132 | } |
129 | 133 |
107 | 107 | return false; |
108 | 108 | } |
109 | 109 | |
110 | return true;//os; | |
110 | return !os.fail(); | |
111 | 111 | } |
112 | 112 | |
113 | 113 | try |
158 | 158 | Ofstream->close(); |
159 | 159 | } |
160 | 160 | |
161 | return true; | |
161 | return !os.fail(); | |
162 | 162 | } |
163 | 163 | |
164 | 164 | void Writer::SetFileName(const char *filename) |
284 | 284 | else if( PF == PixelFormat::SINGLEBIT ) |
285 | 285 | { |
286 | 286 | assert( PF.GetSamplesPerPixel() == 1 ); |
287 | unsigned int save = mul; | |
288 | save /= 8; | |
289 | assert( save * 8 == mul ); | |
287 | const size_t bytesPerRow = Dimensions[0] / 8 + (Dimensions[0] % 8 != 0 ? 1 : 0); | |
288 | unsigned int save = bytesPerRow * Dimensions[1]; | |
289 | if( NumberOfDimensions > 2 ) | |
290 | save *= Dimensions[2]; | |
291 | if(Dimensions[0] % 8 == 0 ) | |
292 | assert( save * 8 == mul ); | |
290 | 293 | mul = save; |
291 | 294 | } |
292 | 295 | else if( PF.GetBitsAllocated() % 8 != 0 ) |
17 | 17 | #include <setjmp.h> |
18 | 18 | |
19 | 19 | #define JPEGBITSCodec JPEG12Codec |
20 | #include "gdcmJPEGBITSCodec.cxx" | |
20 | #define my_error_mgr my_error_mgr_12BIT | |
21 | #define JPEGInternals JPEGInternals_12BIT | |
22 | #define my_source_mgr my_source_mgr_12BIT | |
23 | #define my_destination_mgr my_destination_mgr_12BIT | |
24 | #include "gdcmJPEGBITSCodec.hxx" |
18 | 18 | namespace gdcm |
19 | 19 | { |
20 | 20 | |
21 | class JPEGInternals; | |
21 | class JPEGInternals_12BIT; | |
22 | 22 | class ByteValue; |
23 | 23 | /** |
24 | 24 | * \brief Class to do JPEG 12bits (lossy & lossless) |
40 | 40 | virtual bool EncodeBuffer(std::ostream &os, const char *data, size_t datalen); |
41 | 41 | |
42 | 42 | private: |
43 | JPEGInternals *Internals; | |
43 | JPEGInternals_12BIT *Internals; | |
44 | 44 | }; |
45 | 45 | |
46 | 46 | } // end namespace gdcm |
17 | 17 | #include <setjmp.h> |
18 | 18 | |
19 | 19 | #define JPEGBITSCodec JPEG16Codec |
20 | #include "gdcmJPEGBITSCodec.cxx" | |
20 | #define my_error_mgr my_error_mgr_16BIT | |
21 | #define JPEGInternals JPEGInternals_16BIT | |
22 | #define my_source_mgr my_source_mgr_16BIT | |
23 | #define my_destination_mgr my_destination_mgr_16BIT | |
24 | #include "gdcmJPEGBITSCodec.hxx" |
18 | 18 | namespace gdcm |
19 | 19 | { |
20 | 20 | |
21 | class JPEGInternals; | |
21 | class JPEGInternals_16BIT; | |
22 | 22 | class ByteValue; |
23 | 23 | /** |
24 | 24 | * \brief Class to do JPEG 16bits (lossless) |
40 | 40 | virtual bool EncodeBuffer(std::ostream &os, const char *data, size_t datalen); |
41 | 41 | |
42 | 42 | private: |
43 | JPEGInternals *Internals; | |
43 | JPEGInternals_16BIT *Internals; | |
44 | 44 | }; |
45 | 45 | |
46 | 46 | } // end namespace gdcm |
17 | 17 | #include <setjmp.h> |
18 | 18 | |
19 | 19 | #define JPEGBITSCodec JPEG8Codec |
20 | #include "gdcmJPEGBITSCodec.cxx" | |
20 | #define my_error_mgr my_error_mgr_8BIT | |
21 | #define JPEGInternals JPEGInternals_8BIT | |
22 | #define my_source_mgr my_source_mgr_8BIT | |
23 | #define my_destination_mgr my_destination_mgr_8BIT | |
24 | #include "gdcmJPEGBITSCodec.hxx" |
18 | 18 | namespace gdcm |
19 | 19 | { |
20 | 20 | |
21 | class JPEGInternals; | |
21 | class JPEGInternals_8BIT; | |
22 | 22 | class ByteValue; |
23 | 23 | /** |
24 | 24 | * \brief Class to do JPEG 8bits (lossy & lossless) |
40 | 40 | virtual bool EncodeBuffer(std::ostream &os, const char *data, size_t datalen); |
41 | 41 | |
42 | 42 | private: |
43 | JPEGInternals *Internals; | |
43 | JPEGInternals_8BIT *Internals; | |
44 | 44 | }; |
45 | 45 | |
46 | 46 | } // end namespace gdcm |
0 | /*========================================================================= | |
1 | ||
2 | Program: GDCM (Grassroots DICOM). A DICOM library | |
3 | ||
4 | Copyright (c) 2006-2011 Mathieu Malaterre | |
5 | All rights reserved. | |
6 | See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. | |
7 | ||
8 | This software is distributed WITHOUT ANY WARRANTY; without even | |
9 | the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR | |
10 | PURPOSE. See the above copyright notice for more information. | |
11 | ||
12 | =========================================================================*/ | |
13 | #include "gdcmTrace.h" | |
14 | #include "gdcmTransferSyntax.h" | |
15 | ||
16 | #include <limits.h> | |
17 | ||
18 | /* | |
19 | * jdatasrc.c | |
20 | * | |
21 | * Copyright (C) 1994-1996, Thomas G. Lane. | |
22 | * This file is part of the Independent JPEG Group's software. | |
23 | * For conditions of distribution and use, see the accompanying README file. | |
24 | * | |
25 | * This file contains decompression data source routines for the case of | |
26 | * reading JPEG data from a file (or any stdio stream). While these routines | |
27 | * are sufficient for most applications, some will want to use a different | |
28 | * source manager. | |
29 | * IMPORTANT: we assume that fread() will correctly transcribe an array of | |
30 | * JOCTETs from 8-bit-wide elements on external storage. If char is wider | |
31 | * than 8 bits on your machine, you may need to do some tweaking. | |
32 | */ | |
33 | ||
34 | /* this is not a core library module, so it doesn't define JPEG_INTERNALS */ | |
35 | ||
36 | namespace gdcm | |
37 | { | |
38 | ||
39 | /* Expanded data source object for stdio input */ | |
40 | ||
41 | typedef struct { | |
42 | struct jpeg_source_mgr pub; /* public fields */ | |
43 | ||
44 | std::istream * infile; /* source stream */ | |
45 | JOCTET * buffer; /* start of buffer */ | |
46 | boolean start_of_file; /* have we gotten any data yet? */ | |
47 | } my_source_mgr; | |
48 | ||
49 | typedef my_source_mgr * my_src_ptr; | |
50 | ||
51 | #define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */ | |
52 | ||
53 | ||
54 | /* | |
55 | * Initialize source --- called by jpeg_read_header | |
56 | * before any data is actually read. | |
57 | */ | |
58 | ||
59 | METHODDEF(void) | |
60 | init_source (j_decompress_ptr cinfo) | |
61 | { | |
62 | my_src_ptr src = (my_src_ptr) cinfo->src; | |
63 | ||
64 | /* We reset the empty-input-file flag for each image, | |
65 | * but we don't clear the input buffer. | |
66 | * This is correct behavior for reading a series of images from one source. | |
67 | */ | |
68 | src->start_of_file = TRUE; | |
69 | } | |
70 | ||
71 | ||
72 | /* | |
73 | * Fill the input buffer --- called whenever buffer is emptied. | |
74 | * | |
75 | * In typical applications, this should read fresh data into the buffer | |
76 | * (ignoring the current state of next_input_byte & bytes_in_buffer), | |
77 | * reset the pointer & count to the start of the buffer, and return TRUE | |
78 | * indicating that the buffer has been reloaded. It is not necessary to | |
79 | * fill the buffer entirely, only to obtain at least one more byte. | |
80 | * | |
81 | * There is no such thing as an EOF return. If the end of the file has been | |
82 | * reached, the routine has a choice of ERREXIT() or inserting fake data into | |
83 | * the buffer. In most cases, generating a warning message and inserting a | |
84 | * fake EOI marker is the best course of action --- this will allow the | |
85 | * decompressor to output however much of the image is there. However, | |
86 | * the resulting error message is misleading if the real problem is an empty | |
87 | * input file, so we handle that case specially. | |
88 | * | |
89 | * In applications that need to be able to suspend compression due to input | |
90 | * not being available yet, a FALSE return indicates that no more data can be | |
91 | * obtained right now, but more may be forthcoming later. In this situation, | |
92 | * the decompressor will return to its caller (with an indication of the | |
93 | * number of scanlines it has read, if any). The application should resume | |
94 | * decompression after it has loaded more data into the input buffer. Note | |
95 | * that there are substantial restrictions on the use of suspension --- see | |
96 | * the documentation. | |
97 | * | |
98 | * When suspending, the decompressor will back up to a convenient restart point | |
99 | * (typically the start of the current MCU). next_input_byte & bytes_in_buffer | |
100 | * indicate where the restart point will be if the current call returns FALSE. | |
101 | * Data beyond this point must be rescanned after resumption, so move it to | |
102 | * the front of the buffer rather than discarding it. | |
103 | */ | |
104 | ||
105 | METHODDEF(boolean) | |
106 | fill_input_buffer (j_decompress_ptr cinfo) | |
107 | { | |
108 | my_src_ptr src = (my_src_ptr) cinfo->src; | |
109 | size_t nbytes; | |
110 | ||
111 | //FIXME FIXME FIXME FIXME FIXME | |
112 | //nbytes = JFREAD(src->infile, src->buffer, INPUT_BUF_SIZE); | |
113 | std::streampos pos = src->infile->tellg(); | |
114 | std::streampos end = src->infile->seekg(0, std::ios::end).tellg(); | |
115 | src->infile->seekg(pos, std::ios::beg); | |
116 | //FIXME FIXME FIXME FIXME FIXME | |
117 | if( end == pos ) | |
118 | { | |
119 | /* Start the I/O suspension simply by returning false here: */ | |
120 | return FALSE; | |
121 | } | |
122 | if( (end - pos) < INPUT_BUF_SIZE ) | |
123 | { | |
124 | src->infile->read( (char*)src->buffer, (size_t)(end - pos) ); | |
125 | } | |
126 | else | |
127 | { | |
128 | src->infile->read( (char*)src->buffer, INPUT_BUF_SIZE); | |
129 | } | |
130 | ||
131 | std::streamsize gcount = src->infile->gcount(); | |
132 | assert(gcount < INT_MAX); | |
133 | nbytes = (size_t)gcount; | |
134 | ||
135 | if (nbytes <= 0) { | |
136 | if (src->start_of_file) /* Treat empty input file as fatal error */ | |
137 | ERREXIT(cinfo, JERR_INPUT_EMPTY); | |
138 | WARNMS(cinfo, JWRN_JPEG_EOF); | |
139 | /* Insert a fake EOI marker */ | |
140 | src->buffer[0] = (JOCTET) 0xFF; | |
141 | src->buffer[1] = (JOCTET) JPEG_EOI; | |
142 | nbytes = 2; | |
143 | } | |
144 | ||
145 | src->pub.next_input_byte = src->buffer; | |
146 | src->pub.bytes_in_buffer = nbytes; | |
147 | src->start_of_file = FALSE; | |
148 | ||
149 | return TRUE; | |
150 | } | |
151 | ||
152 | ||
153 | /* | |
154 | * Skip data --- used to skip over a potentially large amount of | |
155 | * uninteresting data (such as an APPn marker). | |
156 | * | |
157 | * Writers of suspendable-input applications must note that skip_input_data | |
158 | * is not granted the right to give a suspension return. If the skip extends | |
159 | * beyond the data currently in the buffer, the buffer can be marked empty so | |
160 | * that the next read will cause a fill_input_buffer call that can suspend. | |
161 | * Arranging for additional bytes to be discarded before reloading the input | |
162 | * buffer is the application writer's problem. | |
163 | */ | |
164 | ||
165 | METHODDEF(void) | |
166 | skip_input_data (j_decompress_ptr cinfo, long num_bytes) | |
167 | { | |
168 | my_src_ptr src = (my_src_ptr) cinfo->src; | |
169 | ||
170 | /* Just a dumb implementation for now. Could use fseek() except | |
171 | * it doesn't work on pipes. Not clear that being smart is worth | |
172 | * any trouble anyway --- large skips are infrequent. | |
173 | */ | |
174 | if (num_bytes > 0) { | |
175 | while (num_bytes > (long) src->pub.bytes_in_buffer) { | |
176 | num_bytes -= (long) src->pub.bytes_in_buffer; | |
177 | (void) fill_input_buffer(cinfo); | |
178 | /* note we assume that fill_input_buffer will never return FALSE, | |
179 | * so suspension need not be handled. | |
180 | */ | |
181 | } | |
182 | src->pub.next_input_byte += (size_t) num_bytes; | |
183 | src->pub.bytes_in_buffer -= (size_t) num_bytes; | |
184 | } | |
185 | } | |
186 | ||
187 | ||
188 | /* | |
189 | * An additional method that can be provided by data source modules is the | |
190 | * resync_to_restart method for error recovery in the presence of RST markers. | |
191 | * For the moment, this source module just uses the default resync method | |
192 | * provided by the JPEG library. That method assumes that no backtracking | |
193 | * is possible. | |
194 | */ | |
195 | ||
196 | ||
197 | /* | |
198 | * Terminate source --- called by jpeg_finish_decompress | |
199 | * after all data has been read. Often a no-op. | |
200 | * | |
201 | * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding | |
202 | * application must deal with any cleanup that should happen even | |
203 | * for error exit. | |
204 | */ | |
205 | ||
206 | METHODDEF(void) | |
207 | term_source (j_decompress_ptr cinfo) | |
208 | { | |
209 | (void)cinfo; | |
210 | /* no work necessary here */ | |
211 | } | |
212 | ||
213 | ||
214 | /* | |
215 | * Prepare for input from a stdio stream. | |
216 | * The caller must have already opened the stream, and is responsible | |
217 | * for closing it after finishing decompression. | |
218 | */ | |
219 | ||
220 | GLOBAL(void) | |
221 | jpeg_stdio_src (j_decompress_ptr cinfo, std::istream & infile, bool flag) | |
222 | { | |
223 | my_src_ptr src; | |
224 | ||
225 | /* The source object and input buffer are made permanent so that a series | |
226 | * of JPEG images can be read from the same file by calling jpeg_stdio_src | |
227 | * only before the first one. (If we discarded the buffer at the end of | |
228 | * one image, we'd likely lose the start of the next one.) | |
229 | * This makes it unsafe to use this manager and a different source | |
230 | * manager serially with the same JPEG object. Caveat programmer. | |
231 | */ | |
232 | if (cinfo->src == NULL) { /* first time for this JPEG object? */ | |
233 | cinfo->src = (struct jpeg_source_mgr *) | |
234 | (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, | |
235 | SIZEOF(my_source_mgr)); | |
236 | src = (my_src_ptr) cinfo->src; | |
237 | src->buffer = (JOCTET *) | |
238 | (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, | |
239 | INPUT_BUF_SIZE * SIZEOF(JOCTET)); | |
240 | } | |
241 | ||
242 | src = (my_src_ptr) cinfo->src; | |
243 | src->pub.init_source = init_source; | |
244 | src->pub.fill_input_buffer = fill_input_buffer; | |
245 | src->pub.skip_input_data = skip_input_data; | |
246 | src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ | |
247 | src->pub.term_source = term_source; | |
248 | src->infile = &infile; | |
249 | if( flag ) | |
250 | { | |
251 | src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ | |
252 | src->pub.next_input_byte = NULL; /* until buffer loaded */ | |
253 | } | |
254 | } | |
255 | ||
256 | } // end namespace gdcm | |
257 | ||
258 | ||
259 | namespace gdcm | |
260 | { | |
261 | /* | |
262 | * The following was copy/paste from example.c | |
263 | */ | |
264 | ||
265 | struct my_error_mgr { | |
266 | struct jpeg_error_mgr pub; /* "public" fields */ | |
267 | jmp_buf setjmp_buffer; /* for return to caller */ | |
268 | }; | |
269 | typedef struct my_error_mgr* my_error_ptr; | |
270 | ||
271 | class JPEGInternals | |
272 | { | |
273 | public: | |
274 | JPEGInternals():cinfo(),jerr(),StateSuspension(0),SampBuffer(0) {} | |
275 | jpeg_decompress_struct cinfo; | |
276 | jpeg_compress_struct cinfo_comp; | |
277 | my_error_mgr jerr; | |
278 | int StateSuspension; | |
279 | void *SampBuffer; | |
280 | }; | |
281 | ||
282 | JPEGBITSCodec::JPEGBITSCodec() | |
283 | { | |
284 | Internals = new JPEGInternals; | |
285 | BitSample = BITS_IN_JSAMPLE; | |
286 | } | |
287 | ||
288 | JPEGBITSCodec::~JPEGBITSCodec() | |
289 | { | |
290 | delete Internals; | |
291 | } | |
292 | ||
293 | /* | |
294 | * Here's the routine that will replace the standard error_exit method: | |
295 | */ | |
296 | extern "C" { | |
297 | METHODDEF(void) my_error_exit (j_common_ptr cinfo) { | |
298 | /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */ | |
299 | my_error_ptr myerr = (my_error_ptr) cinfo->err; | |
300 | ||
301 | /* Always display the message. */ | |
302 | /* We could postpone this until after returning, if we chose. */ | |
303 | (*cinfo->err->output_message) (cinfo); | |
304 | ||
305 | /* Return control to the setjmp point */ | |
306 | longjmp(myerr->setjmp_buffer, 1); | |
307 | } | |
308 | } | |
309 | ||
310 | bool JPEGBITSCodec::GetHeaderInfo(std::istream &is, TransferSyntax &ts) | |
311 | { | |
312 | /* This struct contains the JPEG decompression parameters and pointers to | |
313 | * working space (which is allocated as needed by the JPEG library). | |
314 | */ | |
315 | jpeg_decompress_struct &cinfo = Internals->cinfo; | |
316 | ||
317 | /* We use our private extension JPEG error handler. | |
318 | * Note that this struct must live as long as the main JPEG parameter | |
319 | * struct, to avoid dangling-pointer problems. | |
320 | */ | |
321 | my_error_mgr &jerr = Internals->jerr; | |
322 | /* More stuff */ | |
323 | //FILE * infile; /* source file */ | |
324 | //JSAMPARRAY buffer; /* Output row buffer */ | |
325 | //int row_stride; /* physical row width in output buffer */ | |
326 | ||
327 | if( Internals->StateSuspension == 0 ) | |
328 | { | |
329 | // Step 1: allocate and initialize JPEG decompression object | |
330 | // | |
331 | // We set up the normal JPEG error routines, then override error_exit. | |
332 | cinfo.err = jpeg_std_error(&jerr.pub); | |
333 | jerr.pub.error_exit = my_error_exit; | |
334 | // Establish the setjmp return context for my_error_exit to use. | |
335 | if (setjmp(jerr.setjmp_buffer)) | |
336 | { | |
337 | // If we get here, the JPEG code has signaled an error. | |
338 | // We need to clean up the JPEG object, close the input file, and return. | |
339 | // But first handle the case IJG does not like: | |
340 | if ( jerr.pub.msg_code == JERR_BAD_PRECISION /* 18 */ ) | |
341 | { | |
342 | this->BitSample = jerr.pub.msg_parm.i[0]; | |
343 | assert( this->BitSample == 1 || this->BitSample == 8 || this->BitSample == 12 || this->BitSample == 16 ); | |
344 | assert( this->BitSample == cinfo.data_precision ); | |
345 | } | |
346 | jpeg_destroy_decompress(&cinfo); | |
347 | // TODO: www.dcm4che.org/jira/secure/attachment/10185/ct-implicit-little.dcm | |
348 | // weird Icon Image from GE... | |
349 | return false; | |
350 | } | |
351 | } | |
352 | ||
353 | if( Internals->StateSuspension == 0 ) | |
354 | { | |
355 | // Now we can initialize the JPEG decompression object. | |
356 | jpeg_create_decompress(&cinfo); | |
357 | ||
358 | // Step 2: specify data source (eg, a file) | |
359 | jpeg_stdio_src(&cinfo, is, true); | |
360 | } | |
361 | else | |
362 | { | |
363 | jpeg_stdio_src(&cinfo, is, false); | |
364 | } | |
365 | ||
366 | /* Step 3: read file parameters with jpeg_read_header() */ | |
367 | ||
368 | if ( Internals->StateSuspension < 2 ) | |
369 | { | |
370 | if( jpeg_read_header(&cinfo, TRUE) == JPEG_SUSPENDED ) | |
371 | { | |
372 | Internals->StateSuspension = 2; | |
373 | } | |
374 | // First of all are we using the proper JPEG decoder (correct bit sample): | |
375 | if( jerr.pub.num_warnings ) | |
376 | { | |
377 | if ( jerr.pub.msg_code == 128 ) | |
378 | { | |
379 | this->BitSample = jerr.pub.msg_parm.i[0]; | |
380 | jpeg_destroy_decompress(&cinfo); | |
381 | return false; | |
382 | } | |
383 | else | |
384 | { | |
385 | assert( 0 ); | |
386 | } | |
387 | } | |
388 | this->Dimensions[1] = cinfo.image_height; /* Number of rows in image */ | |
389 | this->Dimensions[0] = cinfo.image_width; /* Number of columns in image */ | |
390 | ||
391 | int prep = this->PF.GetPixelRepresentation(); | |
392 | //this->BitSample = cinfo.data_precision; | |
393 | int precision = cinfo.data_precision; | |
394 | // if lossy it should only be 8 or 12, but for lossless it can be [2-16] | |
395 | if( precision == 1 ) | |
396 | { | |
397 | // lossless ! | |
398 | this->PF = PixelFormat( PixelFormat::SINGLEBIT ); | |
399 | } | |
400 | else if( precision <= 8 ) | |
401 | { | |
402 | this->PF = PixelFormat( PixelFormat::UINT8 ); | |
403 | } | |
404 | else if( precision <= 12 ) | |
405 | { | |
406 | this->PF = PixelFormat( PixelFormat::UINT12 ); | |
407 | } | |
408 | else if( precision <= 16 ) | |
409 | { | |
410 | // lossless ! | |
411 | this->PF = PixelFormat( PixelFormat::UINT16 ); | |
412 | } | |
413 | else | |
414 | { | |
415 | assert( 0 ); | |
416 | } | |
417 | this->PF.SetPixelRepresentation( (uint16_t)prep ); | |
418 | this->PF.SetBitsStored( (uint16_t)precision ); | |
419 | assert( (precision - 1) >= 0 ); | |
420 | this->PF.SetHighBit( (uint16_t)(precision - 1) ); | |
421 | ||
422 | this->PlanarConfiguration = 0; | |
423 | // Let's check the color space: | |
424 | // JCS_UNKNOWN -> 0 | |
425 | // JCS_GRAYSCALE, /* monochrome */ | |
426 | // JCS_RGB, /* red/green/blue */ | |
427 | // JCS_YCbCr, /* Y/Cb/Cr (also known as YUV) */ | |
428 | // JCS_CMYK, /* C/M/Y/K */ | |
429 | // JCS_YCCK /* Y/Cb/Cr/K */ | |
430 | ||
431 | if( cinfo.jpeg_color_space == JCS_UNKNOWN ) | |
432 | { | |
433 | // I do not know if this possible, it looks like IJG always computes a default | |
434 | if( cinfo.num_components == 1 ) | |
435 | { | |
436 | PI = PhotometricInterpretation::MONOCHROME2; | |
437 | this->PF.SetSamplesPerPixel( 1 ); | |
438 | } | |
439 | else if( cinfo.num_components == 3 ) | |
440 | { | |
441 | PI = PhotometricInterpretation::RGB; | |
442 | this->PF.SetSamplesPerPixel( 3 ); | |
443 | } | |
444 | else | |
445 | { | |
446 | assert( 0 ); | |
447 | } | |
448 | } | |
449 | else if( cinfo.jpeg_color_space == JCS_GRAYSCALE ) | |
450 | { | |
451 | assert( cinfo.num_components == 1 ); | |
452 | PI = PhotometricInterpretation::MONOCHROME2; | |
453 | this->PF.SetSamplesPerPixel( 1 ); | |
454 | } | |
455 | else if( cinfo.jpeg_color_space == JCS_RGB ) | |
456 | { | |
457 | assert( cinfo.num_components == 3 ); | |
458 | PI = PhotometricInterpretation::RGB; | |
459 | this->PF.SetSamplesPerPixel( 3 ); | |
460 | } | |
461 | else if( cinfo.jpeg_color_space == JCS_YCbCr ) | |
462 | { | |
463 | assert( cinfo.num_components == 3 ); | |
464 | PI = PhotometricInterpretation::YBR_FULL_422; | |
465 | if( cinfo.process == JPROC_LOSSLESS ) | |
466 | PI = PhotometricInterpretation::RGB; // wotsit ? | |
467 | this->PF.SetSamplesPerPixel( 3 ); | |
468 | this->PlanarConfiguration = 1; | |
469 | } | |
470 | else if( cinfo.jpeg_color_space == JCS_CMYK ) | |
471 | { | |
472 | assert( cinfo.num_components == 4 ); | |
473 | PI = PhotometricInterpretation::CMYK; | |
474 | this->PF.SetSamplesPerPixel( 4 ); | |
475 | } | |
476 | else if( cinfo.jpeg_color_space == JCS_YCCK ) | |
477 | { | |
478 | assert( cinfo.num_components == 4 ); | |
479 | PI = PhotometricInterpretation::YBR_FULL_422; // 4th plane ?? | |
480 | this->PF.SetSamplesPerPixel( 4 ); | |
481 | assert( 0 ); //TODO | |
482 | } | |
483 | else | |
484 | { | |
485 | assert( 0 ); //TODO | |
486 | } | |
487 | } | |
488 | if( cinfo.process == JPROC_LOSSLESS ) | |
489 | { | |
490 | int predictor = cinfo.Ss; | |
491 | /* not very user friendly... */ | |
492 | switch(predictor) | |
493 | { | |
494 | case 1: | |
495 | ts = TransferSyntax::JPEGLosslessProcess14_1; | |
496 | break; | |
497 | default: | |
498 | ts = TransferSyntax::JPEGLosslessProcess14; | |
499 | break; | |
500 | } | |
501 | } | |
502 | else if( cinfo.process == JPROC_SEQUENTIAL ) | |
503 | { | |
504 | if( this->BitSample == 8 ) | |
505 | ts = TransferSyntax::JPEGBaselineProcess1; | |
506 | else if( this->BitSample == 12 ) | |
507 | ts = TransferSyntax::JPEGExtendedProcess2_4; | |
508 | } | |
509 | else if( cinfo.process == JPROC_PROGRESSIVE ) | |
510 | { | |
511 | if( this->BitSample == 8 ) | |
512 | { | |
513 | ts = TransferSyntax::JPEGFullProgressionProcess10_12; | |
514 | } | |
515 | else if( this->BitSample == 12 ) | |
516 | { | |
517 | ts = TransferSyntax::JPEGFullProgressionProcess10_12; | |
518 | } | |
519 | else | |
520 | { | |
521 | assert(0); // TODO | |
522 | return false; | |
523 | } | |
524 | } | |
525 | else | |
526 | { | |
527 | assert(0); // TODO | |
528 | return false; | |
529 | } | |
530 | if( cinfo.process == JPROC_LOSSLESS ) | |
531 | { | |
532 | LossyFlag = false; | |
533 | } | |
534 | else | |
535 | { | |
536 | LossyFlag = true; | |
537 | } | |
538 | ||
539 | // Pixel density stuff: | |
540 | /* | |
541 | UINT8 density_unit | |
542 | UINT16 X_density | |
543 | UINT16 Y_density | |
544 | The resolution information to be written into the JFIF marker; | |
545 | not used otherwise. density_unit may be 0 for unknown, | |
546 | 1 for dots/inch, or 2 for dots/cm. The default values are 0,1,1 | |
547 | indicating square pixels of unknown size. | |
548 | */ | |
549 | ||
550 | if( cinfo.density_unit != 0 | |
551 | || cinfo.X_density != 1 | |
552 | || cinfo.Y_density != 1 | |
553 | ) | |
554 | { | |
555 | gdcmWarningMacro( "Pixel Density from JFIF Marker is not supported (for now)" ); | |
556 | //return false; | |
557 | } | |
558 | ||
559 | ||
560 | #if 0 | |
561 | switch ( cinfo.jpeg_color_space ) | |
562 | { | |
563 | case JCS_GRAYSCALE: | |
564 | if( GetPhotometricInterpretation() != PhotometricInterpretation::MONOCHROME1 | |
565 | && GetPhotometricInterpretation() != PhotometricInterpretation::MONOCHROME2 ) | |
566 | { | |
567 | gdcmWarningMacro( "Wrong PhotometricInterpretation. DICOM says: " << | |
568 | GetPhotometricInterpretation() << " but JPEG says: " | |
569 | << cinfo.jpeg_color_space ); | |
570 | //Internals->SetPhotometricInterpretation( PhotometricInterpretation::MONOCHROME2 ); | |
571 | this->PI = PhotometricInterpretation::MONOCHROME2; | |
572 | } | |
573 | break; | |
574 | case JCS_RGB: | |
575 | assert( GetPhotometricInterpretation() == PhotometricInterpretation::RGB ); | |
576 | break; | |
577 | case JCS_YCbCr: | |
578 | if( GetPhotometricInterpretation() != PhotometricInterpretation::YBR_FULL && | |
579 | GetPhotometricInterpretation() != PhotometricInterpretation::YBR_FULL_422 ) | |
580 | { | |
581 | // DermaColorLossLess.dcm (lossless) | |
582 | // LEADTOOLS_FLOWERS-24-RGB-JpegLossy.dcm (lossy) | |
583 | gdcmWarningMacro( "Wrong PhotometricInterpretation. DICOM says: " << | |
584 | GetPhotometricInterpretation() << " but JPEG says: " | |
585 | << cinfo.jpeg_color_space ); | |
586 | // Here it gets nasty since apparently when this occurs lossless means | |
587 | // we should not do any color conversion, but we *might* be breaking | |
588 | // correct DICOM file. | |
589 | // FIXME FIXME | |
590 | /* prevent the library from performing any color space conversion */ | |
591 | if ( cinfo.process == JPROC_LOSSLESS ) | |
592 | { | |
593 | cinfo.jpeg_color_space = JCS_UNKNOWN; | |
594 | cinfo.out_color_space = JCS_UNKNOWN; | |
595 | } | |
596 | } | |
597 | break; | |
598 | default: | |
599 | assert(0); | |
600 | return false; | |
601 | } | |
602 | //assert( cinfo.data_precision == BITS_IN_JSAMPLE ); | |
603 | //assert( cinfo.data_precision == this->BitSample ); | |
604 | ||
605 | /* Step 4: set parameters for decompression */ | |
606 | /* no op */ | |
607 | } | |
608 | ||
609 | /* Step 5: Start decompressor */ | |
610 | ||
611 | if (Internals->StateSuspension < 3 ) | |
612 | { | |
613 | if ( jpeg_start_decompress(&cinfo) == FALSE ) | |
614 | { | |
615 | /* Suspension: jpeg_start_decompress */ | |
616 | Internals->StateSuspension = 3; | |
617 | } | |
618 | ||
619 | /* We may need to do some setup of our own at this point before reading | |
620 | * the data. After jpeg_start_decompress() we have the correct scaled | |
621 | * output image dimensions available, as well as the output colormap | |
622 | * if we asked for color quantization. | |
623 | * In this example, we need to make an output work buffer of the right size. | |
624 | */ | |
625 | /* JSAMPLEs per row in output buffer */ | |
626 | row_stride = cinfo.output_width * cinfo.output_components; | |
627 | row_stride *= sizeof(JSAMPLE); | |
628 | /* Make a one-row-high sample array that will go away when done with image */ | |
629 | buffer = (*cinfo.mem->alloc_sarray) | |
630 | ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); | |
631 | ||
632 | /* Save the buffer in case of suspension to be able to reuse it later: */ | |
633 | Internals->SampBuffer = buffer; | |
634 | } | |
635 | else | |
636 | { | |
637 | /* JSAMPLEs per row in output buffer */ | |
638 | row_stride = cinfo.output_width * cinfo.output_components; | |
639 | row_stride *= sizeof(JSAMPLE); | |
640 | ||
641 | /* Suspension: re-use the buffer: */ | |
642 | buffer = (JSAMPARRAY)Internals->SampBuffer; | |
643 | } | |
644 | ||
645 | /* Step 6: while (scan lines remain to be read) */ | |
646 | /* jpeg_read_scanlines(...); */ | |
647 | ||
648 | /* Here we use the library's state variable cinfo.output_scanline as the | |
649 | * loop counter, so that we don't have to keep track ourselves. | |
650 | */ | |
651 | while (cinfo.output_scanline < cinfo.output_height) { | |
652 | /* jpeg_read_scanlines expects an array of pointers to scanlines. | |
653 | * Here the array is only one element long, but you could ask for | |
654 | * more than one scanline at a time if that's more convenient. | |
655 | */ | |
656 | if( jpeg_read_scanlines(&cinfo, buffer, 1) == 0 ) | |
657 | { | |
658 | /* Suspension in jpeg_read_scanlines */ | |
659 | Internals->StateSuspension = 3; | |
660 | return true; | |
661 | } | |
662 | os.write((char*)buffer[0], row_stride); | |
663 | } | |
664 | ||
665 | /* Step 7: Finish decompression */ | |
666 | ||
667 | if( jpeg_finish_decompress(&cinfo) == FALSE ) | |
668 | { | |
669 | /* Suspension: jpeg_finish_decompress */ | |
670 | Internals->StateSuspension = 4; | |
671 | } | |
672 | #endif | |
673 | ||
674 | /* Step 8: Release JPEG decompression object */ | |
675 | ||
676 | /* This is an important step since it will release a good deal of memory. */ | |
677 | jpeg_destroy_decompress(&cinfo); | |
678 | ||
679 | /* After finish_decompress, we can close the input file. | |
680 | * Here we postpone it until after no more JPEG errors are possible, | |
681 | * so as to simplify the setjmp error logic above. (Actually, I don't | |
682 | * think that jpeg_destroy can do an error exit, but why assume anything...) | |
683 | */ | |
684 | //fclose(infile); | |
685 | ||
686 | /* At this point you may want to check to see whether any corrupt-data | |
687 | * warnings occurred (test whether jerr.pub.num_warnings is nonzero). | |
688 | */ | |
689 | /* In any case make sure the we reset the internal state suspension */ | |
690 | Internals->StateSuspension = 0; | |
691 | ||
692 | /* And we're done! */ | |
693 | return true; | |
694 | ||
695 | } | |
696 | ||
697 | /* | |
698 | * Note: see dcmdjpeg +cn option to avoid the YBR => RGB loss | |
699 | */ | |
700 | bool JPEGBITSCodec::DecodeByStreams(std::istream &is, std::ostream &os) | |
701 | { | |
702 | /* This struct contains the JPEG decompression parameters and pointers to | |
703 | * working space (which is allocated as needed by the JPEG library). | |
704 | */ | |
705 | jpeg_decompress_struct &cinfo = Internals->cinfo; | |
706 | ||
707 | /* We use our private extension JPEG error handler. | |
708 | * Note that this struct must live as long as the main JPEG parameter | |
709 | * struct, to avoid dangling-pointer problems. | |
710 | */ | |
711 | my_error_mgr &jerr = Internals->jerr; | |
712 | /* More stuff */ | |
713 | //FILE * infile; /* source file */ | |
714 | JSAMPARRAY buffer; /* Output row buffer */ | |
715 | size_t row_stride; /* physical row width in output buffer */ | |
716 | ||
717 | if( Internals->StateSuspension == 0 ) | |
718 | { | |
719 | // Step 1: allocate and initialize JPEG decompression object | |
720 | // | |
721 | // We set up the normal JPEG error routines, then override error_exit. | |
722 | cinfo.err = jpeg_std_error(&jerr.pub); | |
723 | jerr.pub.error_exit = my_error_exit; | |
724 | // Establish the setjmp return context for my_error_exit to use. | |
725 | if (setjmp(jerr.setjmp_buffer)) | |
726 | { | |
727 | // If we get here, the JPEG code has signaled an error. | |
728 | // We need to clean up the JPEG object, close the input file, and return. | |
729 | // But first handle the case IJG does not like: | |
730 | if ( jerr.pub.msg_code == JERR_BAD_PRECISION /* 18 */ ) | |
731 | { | |
732 | this->BitSample = jerr.pub.msg_parm.i[0]; | |
733 | //assert( this->BitSample == 8 || this->BitSample == 12 || this->BitSample == 16 ); | |
734 | } | |
735 | jpeg_destroy_decompress(&cinfo); | |
736 | // TODO: www.dcm4che.org/jira/secure/attachment/10185/ct-implicit-little.dcm | |
737 | // weird Icon Image from GE... | |
738 | return false; | |
739 | } | |
740 | } | |
741 | ||
742 | if( Internals->StateSuspension == 0 ) | |
743 | { | |
744 | // Now we can initialize the JPEG decompression object. | |
745 | jpeg_create_decompress(&cinfo); | |
746 | ||
747 | // Step 2: specify data source (eg, a file) | |
748 | jpeg_stdio_src(&cinfo, is, true); | |
749 | } | |
750 | else | |
751 | { | |
752 | jpeg_stdio_src(&cinfo, is, false); | |
753 | } | |
754 | ||
755 | /* Step 3: read file parameters with jpeg_read_header() */ | |
756 | ||
757 | if ( Internals->StateSuspension < 2 ) | |
758 | { | |
759 | if( jpeg_read_header(&cinfo, TRUE) == JPEG_SUSPENDED ) | |
760 | { | |
761 | Internals->StateSuspension = 2; | |
762 | } | |
763 | // First of all are we using the proper JPEG decoder (correct bit sample): | |
764 | if( jerr.pub.num_warnings ) | |
765 | { | |
766 | // PHILIPS_Gyroscan-12-MONO2-Jpeg_Lossless.dcm | |
767 | if ( jerr.pub.msg_code == JWRN_MUST_DOWNSCALE ) | |
768 | { | |
769 | // PHILIPS_Gyroscan-12-Jpeg_Extended_Process_2_4.dcm | |
770 | // PHILIPS_Gyroscan-12-MONO2-Jpeg_Lossless.dcm | |
771 | // MARCONI_MxTWin-12-MONO2-JpegLossless-ZeroLengthSQ.dcm | |
772 | // LJPEG_BuginGDCM12.dcm | |
773 | gdcmDebugMacro( "JWRN_MUST_DOWNSCALE" ); | |
774 | this->BitSample = jerr.pub.msg_parm.i[0]; | |
775 | assert( cinfo.data_precision == this->BitSample ); | |
776 | jpeg_destroy_decompress(&cinfo); | |
777 | return false; | |
778 | } | |
779 | else | |
780 | { | |
781 | assert( 0 ); | |
782 | } | |
783 | } | |
784 | // Let's check the color space: | |
785 | // JCS_UNKNOWN -> 0 | |
786 | // JCS_GRAYSCALE | |
787 | // JCS_RGB | |
788 | // JCS_YCbCr | |
789 | // JCS_CMYK | |
790 | // JCS_YCCK | |
791 | ||
792 | // Sanity checks: | |
793 | const unsigned int * dims = this->GetDimensions(); | |
794 | if( cinfo.image_width != dims[0] | |
795 | || cinfo.image_height != dims[1] ) | |
796 | { | |
797 | gdcmWarningMacro( "dimension mismatch. JPEG is " << | |
798 | cinfo.image_width << "," << cinfo.image_height << " while DICOM " << dims[0] << | |
799 | "," << dims[1] ); | |
800 | //this->Dimensions[0] = cinfo.image_width; | |
801 | //this->Dimensions[1] = cinfo.image_height; | |
802 | /* | |
803 | * Long story short, the real issue is that class such as ImageRegionReader expect to read the | |
804 | * image information without ever touching the JPEG codestream... | |
805 | */ | |
806 | return false; | |
807 | } | |
808 | assert( cinfo.image_width == dims[0] ); | |
809 | assert( cinfo.image_height == dims[1] ); | |
810 | ||
811 | switch ( cinfo.jpeg_color_space ) | |
812 | { | |
813 | case JCS_GRAYSCALE: | |
814 | if( GetPhotometricInterpretation() != PhotometricInterpretation::MONOCHROME1 | |
815 | && GetPhotometricInterpretation() != PhotometricInterpretation::MONOCHROME2 ) | |
816 | { | |
817 | gdcmWarningMacro( "Wrong PhotometricInterpretation. DICOM says: " << | |
818 | GetPhotometricInterpretation() << " but JPEG says: " | |
819 | << (int)cinfo.jpeg_color_space ); | |
820 | //Internals->SetPhotometricInterpretation( PhotometricInterpretation::MONOCHROME2 ); | |
821 | this->PI = PhotometricInterpretation::MONOCHROME2; | |
822 | } | |
823 | break; | |
824 | case JCS_RGB: | |
825 | //assert( GetPhotometricInterpretation() == PhotometricInterpretation::RGB ); | |
826 | if ( cinfo.process == JPROC_LOSSLESS ) | |
827 | { | |
828 | cinfo.jpeg_color_space = JCS_UNKNOWN; | |
829 | cinfo.out_color_space = JCS_UNKNOWN; | |
830 | } | |
831 | if( GetPhotometricInterpretation() == PhotometricInterpretation::YBR_RCT | |
832 | || GetPhotometricInterpretation() == PhotometricInterpretation::YBR_ICT ) | |
833 | this->PI = PhotometricInterpretation::RGB; | |
834 | break; | |
835 | case JCS_YCbCr: | |
836 | if( GetPhotometricInterpretation() != PhotometricInterpretation::YBR_FULL && | |
837 | GetPhotometricInterpretation() != PhotometricInterpretation::YBR_FULL_422 ) | |
838 | { | |
839 | // DermaColorLossLess.dcm (lossless) | |
840 | // LEADTOOLS_FLOWERS-24-RGB-JpegLossy.dcm (lossy) | |
841 | gdcmWarningMacro( "Wrong PhotometricInterpretation. DICOM says: " << | |
842 | GetPhotometricInterpretation() << " but JPEG says: " | |
843 | << (int)cinfo.jpeg_color_space ); | |
844 | // Here it gets nasty since apparently when this occurs lossless means | |
845 | // we should not do any color conversion, but we *might* be breaking | |
846 | // correct DICOM file. | |
847 | // FIXME FIXME | |
848 | /* prevent the library from performing any color space conversion */ | |
849 | cinfo.jpeg_color_space = JCS_UNKNOWN; | |
850 | cinfo.out_color_space = JCS_UNKNOWN; | |
851 | } | |
852 | if ( cinfo.process == JPROC_LOSSLESS ) | |
853 | { | |
854 | //cinfo.jpeg_color_space = JCS_UNKNOWN; | |
855 | //cinfo.out_color_space = JCS_UNKNOWN; | |
856 | } | |
857 | if( GetPhotometricInterpretation() == PhotometricInterpretation::YBR_FULL | |
858 | || GetPhotometricInterpretation() == PhotometricInterpretation::YBR_FULL_422 ) | |
859 | { | |
860 | cinfo.jpeg_color_space = JCS_UNKNOWN; | |
861 | cinfo.out_color_space = JCS_UNKNOWN; | |
862 | //this->PlanarConfiguration = 1; | |
863 | } | |
864 | break; | |
865 | case JCS_CMYK: | |
866 | assert( GetPhotometricInterpretation() == PhotometricInterpretation::CMYK ); | |
867 | if ( cinfo.process == JPROC_LOSSLESS ) | |
868 | { | |
869 | cinfo.jpeg_color_space = JCS_UNKNOWN; | |
870 | cinfo.out_color_space = JCS_UNKNOWN; | |
871 | } | |
872 | break; | |
873 | case JCS_UNKNOWN: | |
874 | if ( cinfo.process == JPROC_LOSSLESS ) | |
875 | { | |
876 | cinfo.jpeg_color_space = JCS_UNKNOWN; | |
877 | cinfo.out_color_space = JCS_UNKNOWN; | |
878 | } | |
879 | break; | |
880 | default: | |
881 | assert(0); | |
882 | return false; | |
883 | } | |
884 | //assert( cinfo.data_precision == BITS_IN_JSAMPLE ); | |
885 | //assert( cinfo.data_precision == this->BitSample ); | |
886 | ||
887 | /* Step 4: set parameters for decompression */ | |
888 | /* no op */ | |
889 | } | |
890 | ||
891 | /* Step 5: Start decompressor */ | |
892 | ||
893 | if (Internals->StateSuspension < 3 ) | |
894 | { | |
895 | if ( jpeg_start_decompress(&cinfo) == FALSE ) | |
896 | { | |
897 | /* Suspension: jpeg_start_decompress */ | |
898 | Internals->StateSuspension = 3; | |
899 | } | |
900 | ||
901 | /* We may need to do some setup of our own at this point before reading | |
902 | * the data. After jpeg_start_decompress() we have the correct scaled | |
903 | * output image dimensions available, as well as the output colormap | |
904 | * if we asked for color quantization. | |
905 | * In this example, we need to make an output work buffer of the right size. | |
906 | */ | |
907 | /* JSAMPLEs per row in output buffer */ | |
908 | row_stride = cinfo.output_width * cinfo.output_components; | |
909 | row_stride *= sizeof(JSAMPLE); | |
910 | /* Make a one-row-high sample array that will go away when done with image */ | |
911 | buffer = (*cinfo.mem->alloc_sarray) | |
912 | ((j_common_ptr) &cinfo, JPOOL_IMAGE, (JDIMENSION)row_stride, 1); | |
913 | ||
914 | /* Save the buffer in case of suspension to be able to reuse it later: */ | |
915 | Internals->SampBuffer = buffer; | |
916 | } | |
917 | else | |
918 | { | |
919 | /* JSAMPLEs per row in output buffer */ | |
920 | row_stride = cinfo.output_width * cinfo.output_components; | |
921 | row_stride *= sizeof(JSAMPLE); | |
922 | ||
923 | /* Suspension: re-use the buffer: */ | |
924 | buffer = (JSAMPARRAY)Internals->SampBuffer; | |
925 | } | |
926 | ||
927 | /* Step 6: while (scan lines remain to be read) */ | |
928 | /* jpeg_read_scanlines(...); */ | |
929 | ||
930 | /* Here we use the library's state variable cinfo.output_scanline as the | |
931 | * loop counter, so that we don't have to keep track ourselves. | |
932 | */ | |
933 | while (cinfo.output_scanline < cinfo.output_height) { | |
934 | /* jpeg_read_scanlines expects an array of pointers to scanlines. | |
935 | * Here the array is only one element long, but you could ask for | |
936 | * more than one scanline at a time if that's more convenient. | |
937 | */ | |
938 | if( jpeg_read_scanlines(&cinfo, buffer, 1) == 0 ) | |
939 | { | |
940 | /* Suspension in jpeg_read_scanlines */ | |
941 | Internals->StateSuspension = 3; | |
942 | return true; | |
943 | } | |
944 | os.write((char*)buffer[0], row_stride); | |
945 | } | |
946 | ||
947 | /* Step 7: Finish decompression */ | |
948 | ||
949 | if( jpeg_finish_decompress(&cinfo) == FALSE ) | |
950 | { | |
951 | /* Suspension: jpeg_finish_decompress */ | |
952 | Internals->StateSuspension = 4; | |
953 | return true; | |
954 | } | |
955 | ||
956 | /* we are done decompressing the file, now is a good time to store the type | |
957 | of compression used: lossless or not */ | |
958 | if( cinfo.process == JPROC_LOSSLESS ) | |
959 | { | |
960 | LossyFlag = false; | |
961 | } | |
962 | else | |
963 | { | |
964 | LossyFlag = true; | |
965 | } | |
966 | ||
967 | /* Step 8: Release JPEG decompression object */ | |
968 | ||
969 | /* This is an important step since it will release a good deal of memory. */ | |
970 | jpeg_destroy_decompress(&cinfo); | |
971 | ||
972 | /* After finish_decompress, we can close the input file. | |
973 | * Here we postpone it until after no more JPEG errors are possible, | |
974 | * so as to simplify the setjmp error logic above. (Actually, I don't | |
975 | * think that jpeg_destroy can do an error exit, but why assume anything...) | |
976 | */ | |
977 | //fclose(infile); | |
978 | ||
979 | /* At this point you may want to check to see whether any corrupt-data | |
980 | * warnings occurred (test whether jerr.pub.num_warnings is nonzero). | |
981 | */ | |
982 | /* gdcmData/D_CLUNIE_MR4_JPLY.dcm produces a single warning: | |
983 | * Invalid SOS parameters for sequential JPEG | |
984 | * Be nice with this one: | |
985 | */ | |
986 | if( jerr.pub.num_warnings > 1 ) | |
987 | { | |
988 | gdcmErrorMacro( "Too many warning during decompression of JPEG stream: " << jerr.pub.num_warnings ); | |
989 | return false; | |
990 | } | |
991 | /* In any case make sure the we reset the internal state suspension */ | |
992 | Internals->StateSuspension = 0; | |
993 | ||
994 | /* And we're done! */ | |
995 | return true; | |
996 | } | |
997 | ||
998 | /* | |
999 | * jdatadst.c | |
1000 | * | |
1001 | * Copyright (C) 1994-1996, Thomas G. Lane. | |
1002 | * This file is part of the Independent JPEG Group's software. | |
1003 | * For conditions of distribution and use, see the accompanying README file. | |
1004 | * | |
1005 | * This file contains compression data destination routines for the case of | |
1006 | * emitting JPEG data to a file (or any stdio stream). While these routines | |
1007 | * are sufficient for most applications, some will want to use a different | |
1008 | * destination manager. | |
1009 | * IMPORTANT: we assume that fwrite() will correctly transcribe an array of | |
1010 | * JOCTETs into 8-bit-wide elements on external storage. If char is wider | |
1011 | * than 8 bits on your machine, you may need to do some tweaking. | |
1012 | */ | |
1013 | ||
1014 | /** | |
1015 | * \brief very low level C 'structure', used to decode jpeg file | |
1016 | * Should not appear in the Doxygen supplied documentation | |
1017 | */ | |
1018 | typedef struct { | |
1019 | struct jpeg_destination_mgr pub; /* public fields */ | |
1020 | ||
1021 | std::ostream * outfile; /* target stream */ | |
1022 | JOCTET * buffer; /* start of buffer */ | |
1023 | } my_destination_mgr; | |
1024 | ||
1025 | typedef my_destination_mgr * my_dest_ptr; | |
1026 | ||
1027 | #define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */ | |
1028 | ||
1029 | /* | |
1030 | * Initialize destination --- called by jpeg_start_compress | |
1031 | * before any data is actually written. | |
1032 | */ | |
1033 | ||
1034 | METHODDEF(void) | |
1035 | init_destination (j_compress_ptr cinfo) | |
1036 | { | |
1037 | my_dest_ptr dest = (my_dest_ptr) cinfo->dest; | |
1038 | ||
1039 | /* Allocate the output buffer --- it will be released when done with image */ | |
1040 | dest->buffer = (JOCTET *) | |
1041 | (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, | |
1042 | OUTPUT_BUF_SIZE * SIZEOF(JOCTET)); | |
1043 | ||
1044 | dest->pub.next_output_byte = dest->buffer; | |
1045 | dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; | |
1046 | } | |
1047 | ||
1048 | ||
1049 | /* | |
1050 | * Empty the output buffer --- called whenever buffer fills up. | |
1051 | * | |
1052 | * In typical applications, this should write the entire output buffer | |
1053 | * (ignoring the current state of next_output_byte & free_in_buffer), | |
1054 | * reset the pointer & count to the start of the buffer, and return TRUE | |
1055 | * indicating that the buffer has been dumped. | |
1056 | * | |
1057 | * In applications that need to be able to suspend compression due to output | |
1058 | * overrun, a FALSE return indicates that the buffer cannot be emptied now. | |
1059 | * In this situation, the compressor will return to its caller (possibly with | |
1060 | * an indication that it has not accepted all the supplied scanlines). The | |
1061 | * application should resume compression after it has made more room in the | |
1062 | * output buffer. Note that there are substantial restrictions on the use of | |
1063 | * suspension --- see the documentation. | |
1064 | * | |
1065 | * When suspending, the compressor will back up to a convenient restart point | |
1066 | * (typically the start of the current MCU). next_output_byte & free_in_buffer | |
1067 | * indicate where the restart point will be if the current call returns FALSE. | |
1068 | * Data beyond this point will be regenerated after resumption, so do not | |
1069 | * write it out when emptying the buffer externally. | |
1070 | */ | |
1071 | ||
1072 | METHODDEF(boolean) | |
1073 | empty_output_buffer (j_compress_ptr cinfo) | |
1074 | { | |
1075 | my_dest_ptr dest = (my_dest_ptr) cinfo->dest; | |
1076 | ||
1077 | //if (JFWRITE(dest->outfile, dest->buffer, OUTPUT_BUF_SIZE) != | |
1078 | // (size_t) OUTPUT_BUF_SIZE) | |
1079 | // ERREXIT(cinfo, JERR_FILE_WRITE); | |
1080 | size_t output_buf_size = OUTPUT_BUF_SIZE; | |
1081 | if( !dest->outfile->write((char*)dest->buffer, output_buf_size) ) | |
1082 | { | |
1083 | ERREXIT(cinfo, JERR_FILE_WRITE); | |
1084 | } | |
1085 | ||
1086 | dest->pub.next_output_byte = dest->buffer; | |
1087 | dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; | |
1088 | ||
1089 | return TRUE; | |
1090 | } | |
1091 | ||
1092 | ||
1093 | /* | |
1094 | * Terminate destination --- called by jpeg_finish_compress | |
1095 | * after all data has been written. Usually needs to flush buffer. | |
1096 | * | |
1097 | * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding | |
1098 | * application must deal with any cleanup that should happen even | |
1099 | * for error exit. | |
1100 | */ | |
1101 | ||
1102 | METHODDEF(void) | |
1103 | term_destination (j_compress_ptr cinfo) | |
1104 | { | |
1105 | my_dest_ptr dest = (my_dest_ptr) cinfo->dest; | |
1106 | size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer; | |
1107 | ||
1108 | /* Write any data remaining in the buffer */ | |
1109 | if (datacount > 0) { | |
1110 | //if (JFWRITE(dest->outfile, dest->buffer, datacount) != datacount) | |
1111 | // ERREXIT(cinfo, JERR_FILE_WRITE); | |
1112 | if( !dest->outfile->write((char*)dest->buffer, datacount) ) | |
1113 | ERREXIT(cinfo, JERR_FILE_WRITE); | |
1114 | } | |
1115 | //fflush(dest->outfile); | |
1116 | dest->outfile->flush(); | |
1117 | /* Make sure we wrote the output file OK */ | |
1118 | //if (ferror(dest->outfile)) | |
1119 | if (dest->outfile->fail()) | |
1120 | ERREXIT(cinfo, JERR_FILE_WRITE); | |
1121 | } | |
1122 | ||
1123 | ||
1124 | /* | |
1125 | * Prepare for output to a stdio stream. | |
1126 | * The caller must have already opened the stream, and is responsible | |
1127 | * for closing it after finishing compression. | |
1128 | */ | |
1129 | ||
1130 | GLOBAL(void) | |
1131 | jpeg_stdio_dest (j_compress_ptr cinfo, /*FILE * */ std::ostream * outfile) | |
1132 | { | |
1133 | my_dest_ptr dest; | |
1134 | ||
1135 | /* The destination object is made permanent so that multiple JPEG images | |
1136 | * can be written to the same file without re-executing jpeg_stdio_dest. | |
1137 | * This makes it dangerous to use this manager and a different destination | |
1138 | * manager serially with the same JPEG object, because their private object | |
1139 | * sizes may be different. Caveat programmer. | |
1140 | */ | |
1141 | if (cinfo->dest == NULL) { /* first time for this JPEG object? */ | |
1142 | cinfo->dest = (struct jpeg_destination_mgr *) | |
1143 | (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, | |
1144 | SIZEOF(my_destination_mgr)); | |
1145 | } | |
1146 | ||
1147 | dest = (my_dest_ptr) cinfo->dest; | |
1148 | dest->pub.init_destination = init_destination; | |
1149 | dest->pub.empty_output_buffer = empty_output_buffer; | |
1150 | dest->pub.term_destination = term_destination; | |
1151 | dest->outfile = outfile; | |
1152 | } | |
1153 | ||
1154 | /* | |
1155 | * Sample routine for JPEG compression. We assume that the target file name | |
1156 | * and a compression quality factor are passed in. | |
1157 | */ | |
1158 | ||
1159 | bool JPEGBITSCodec::InternalCode(const char* input, unsigned long len, std::ostream &os) | |
1160 | { | |
1161 | int quality = 100; (void)len; | |
1162 | (void)quality; | |
1163 | JSAMPLE * image_buffer = (JSAMPLE*)input; /* Points to large array of R,G,B-order data */ | |
1164 | const unsigned int *dims = this->GetDimensions(); | |
1165 | int image_height = dims[1]; /* Number of rows in image */ | |
1166 | int image_width = dims[0]; /* Number of columns in image */ | |
1167 | ||
1168 | /* This struct contains the JPEG compression parameters and pointers to | |
1169 | * working space (which is allocated as needed by the JPEG library). | |
1170 | * It is possible to have several such structures, representing multiple | |
1171 | * compression/decompression processes, in existence at once. We refer | |
1172 | * to any one struct (and its associated working data) as a "JPEG object". | |
1173 | */ | |
1174 | struct jpeg_compress_struct cinfo; | |
1175 | /* This struct represents a JPEG error handler. It is declared separately | |
1176 | * because applications often want to supply a specialized error handler | |
1177 | * (see the second half of this file for an example). But here we just | |
1178 | * take the easy way out and use the standard error handler, which will | |
1179 | * print a message on stderr and call exit() if compression fails. | |
1180 | * Note that this struct must live as long as the main JPEG parameter | |
1181 | * struct, to avoid dangling-pointer problems. | |
1182 | */ | |
1183 | struct jpeg_error_mgr jerr; | |
1184 | /* More stuff */ | |
1185 | //FILE * outfile; /* target file */ | |
1186 | std::ostream * outfile = &os; | |
1187 | JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ | |
1188 | size_t row_stride; /* physical row width in image buffer */ | |
1189 | ||
1190 | /* Step 1: allocate and initialize JPEG compression object */ | |
1191 | ||
1192 | /* We have to set up the error handler first, in case the initialization | |
1193 | * step fails. (Unlikely, but it could happen if you are out of memory.) | |
1194 | * This routine fills in the contents of struct jerr, and returns jerr's | |
1195 | * address which we place into the link field in cinfo. | |
1196 | */ | |
1197 | cinfo.err = jpeg_std_error(&jerr); | |
1198 | /* Now we can initialize the JPEG compression object. */ | |
1199 | jpeg_create_compress(&cinfo); | |
1200 | ||
1201 | /* Step 2: specify data destination (eg, a file) */ | |
1202 | /* Note: steps 2 and 3 can be done in either order. */ | |
1203 | ||
1204 | /* Here we use the library-supplied code to send compressed data to a | |
1205 | * stdio stream. You can also write your own code to do something else. | |
1206 | * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that | |
1207 | * requires it in order to write binary files. | |
1208 | */ | |
1209 | //if ((outfile = fopen(filename, "wb")) == NULL) { | |
1210 | // fprintf(stderr, "can't open %s\n", filename); | |
1211 | // exit(1); | |
1212 | //} | |
1213 | jpeg_stdio_dest(&cinfo, outfile); | |
1214 | ||
1215 | /* Step 3: set parameters for compression */ | |
1216 | ||
1217 | /* First we supply a description of the input image. | |
1218 | * Four fields of the cinfo struct must be filled in: | |
1219 | */ | |
1220 | cinfo.image_width = image_width; /* image width and height, in pixels */ | |
1221 | cinfo.image_height = image_height; | |
1222 | ||
1223 | switch( this->GetPhotometricInterpretation() ) | |
1224 | { | |
1225 | case PhotometricInterpretation::MONOCHROME1: | |
1226 | case PhotometricInterpretation::MONOCHROME2: | |
1227 | case PhotometricInterpretation::PALETTE_COLOR: | |
1228 | cinfo.input_components = 1; /* # of color components per pixel */ | |
1229 | cinfo.in_color_space = JCS_GRAYSCALE; /* colorspace of input image */ | |
1230 | break; | |
1231 | case PhotometricInterpretation::RGB: | |
1232 | case PhotometricInterpretation::YBR_RCT: | |
1233 | case PhotometricInterpretation::YBR_ICT: | |
1234 | cinfo.input_components = 3; /* # of color components per pixel */ | |
1235 | cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ | |
1236 | break; | |
1237 | case PhotometricInterpretation::YBR_FULL: | |
1238 | case PhotometricInterpretation::YBR_FULL_422: | |
1239 | case PhotometricInterpretation::YBR_PARTIAL_420: | |
1240 | case PhotometricInterpretation::YBR_PARTIAL_422: | |
1241 | cinfo.input_components = 3; /* # of color components per pixel */ | |
1242 | cinfo.in_color_space = JCS_YCbCr; /* colorspace of input image */ | |
1243 | break; | |
1244 | case PhotometricInterpretation::HSV: | |
1245 | case PhotometricInterpretation::ARGB: | |
1246 | case PhotometricInterpretation::CMYK: | |
1247 | // TODO ! | |
1248 | case PhotometricInterpretation::UNKNOWN: | |
1249 | case PhotometricInterpretation::PI_END: // To please compiler | |
1250 | return false; | |
1251 | } | |
1252 | //if ( cinfo.process == JPROC_LOSSLESS ) | |
1253 | // { | |
1254 | // cinfo.in_color_space = JCS_UNKNOWN; | |
1255 | // } | |
1256 | //assert( cinfo.image_height * cinfo.image_width * cinfo.input_components * sizeof(JSAMPLE) == len ); | |
1257 | ||
1258 | /* Now use the library's routine to set default compression parameters. | |
1259 | * (You must set at least cinfo.in_color_space before calling this, | |
1260 | * since the defaults depend on the source color space.) | |
1261 | */ | |
1262 | jpeg_set_defaults(&cinfo); | |
1263 | ||
1264 | /* | |
1265 | * predictor = 1 | |
1266 | * point_transform = 0 | |
1267 | * => lossless transformation. | |
1268 | * Basicaly you need to have point_transform = 0, but you can pick whichever predictor [1...7] you want | |
1269 | * TODO: is there a way to pick the right predictor (best compression/fastest ?) | |
1270 | */ | |
1271 | if( !LossyFlag ) | |
1272 | { | |
1273 | jpeg_simple_lossless (&cinfo, 1, 0); | |
1274 | //jpeg_simple_lossless (&cinfo, 7, 0); | |
1275 | } | |
1276 | ||
1277 | /* Now you can set any non-default parameters you wish to. | |
1278 | * Here we just illustrate the use of quality (quantization table) scaling: | |
1279 | */ | |
1280 | if( !LossyFlag ) | |
1281 | { | |
1282 | assert( Quality == 100 ); | |
1283 | } | |
1284 | jpeg_set_quality(&cinfo, Quality, TRUE /* limit to baseline-JPEG values */); | |
1285 | ||
1286 | /* | |
1287 | * See write_file_header | |
1288 | */ | |
1289 | cinfo.write_JFIF_header = 0; | |
1290 | //cinfo.density_unit = 2; | |
1291 | //cinfo.X_density = 2; | |
1292 | //cinfo.Y_density = 5; | |
1293 | ||
1294 | /* Step 4: Start compressor */ | |
1295 | ||
1296 | /* TRUE ensures that we will write a complete interchange-JPEG file. | |
1297 | * Pass TRUE unless you are very sure of what you're doing. | |
1298 | */ | |
1299 | jpeg_start_compress(&cinfo, TRUE); | |
1300 | ||
1301 | /* Step 5: while (scan lines remain to be written) */ | |
1302 | /* jpeg_write_scanlines(...); */ | |
1303 | ||
1304 | /* Here we use the library's state variable cinfo.next_scanline as the | |
1305 | * loop counter, so that we don't have to keep track ourselves. | |
1306 | * To keep things simple, we pass one scanline per call; you can pass | |
1307 | * more if you wish, though. | |
1308 | */ | |
1309 | row_stride = image_width * cinfo.input_components; /* JSAMPLEs per row in image_buffer */ | |
1310 | ||
1311 | if( this->GetPlanarConfiguration() == 0 ) | |
1312 | { | |
1313 | while (cinfo.next_scanline < cinfo.image_height) { | |
1314 | /* jpeg_write_scanlines expects an array of pointers to scanlines. | |
1315 | * Here the array is only one element long, but you could pass | |
1316 | * more than one scanline at a time if that's more convenient. | |
1317 | */ | |
1318 | row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride]; | |
1319 | (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); | |
1320 | } | |
1321 | } | |
1322 | else | |
1323 | { | |
1324 | /* | |
1325 | * warning: Need to read C.7.6.3.1.3 Planar Configuration (see note about Planar Configuration dummy value) | |
1326 | */ | |
1327 | JSAMPLE *tempbuffer = (JSAMPLE*)malloc( row_stride * sizeof(JSAMPLE) ); | |
1328 | row_pointer[0] = tempbuffer; | |
1329 | int offset = image_height * image_width; | |
1330 | while (cinfo.next_scanline < cinfo.image_height) { | |
1331 | assert( row_stride % 3 == 0 ); | |
1332 | JSAMPLE* ptempbuffer = tempbuffer; | |
1333 | JSAMPLE* red = image_buffer + cinfo.next_scanline * row_stride / 3; | |
1334 | JSAMPLE* green = image_buffer + cinfo.next_scanline * row_stride / 3 + offset; | |
1335 | JSAMPLE* blue = image_buffer + cinfo.next_scanline * row_stride / 3 + offset * 2; | |
1336 | for(size_t i = 0; i < row_stride / 3; ++i ) | |
1337 | { | |
1338 | *ptempbuffer++ = *red++; | |
1339 | *ptempbuffer++ = *green++; | |
1340 | *ptempbuffer++ = *blue++; | |
1341 | } | |
1342 | (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); | |
1343 | } | |
1344 | free(tempbuffer); | |
1345 | } | |
1346 | ||
1347 | /* Step 6: Finish compression */ | |
1348 | ||
1349 | jpeg_finish_compress(&cinfo); | |
1350 | /* After finish_compress, we can close the output file. */ | |
1351 | //fclose(outfile); | |
1352 | ||
1353 | /* Step 7: release JPEG compression object */ | |
1354 | ||
1355 | /* This is an important step since it will release a good deal of memory. */ | |
1356 | jpeg_destroy_compress(&cinfo); | |
1357 | ||
1358 | /* And we're done! */ | |
1359 | return true; | |
1360 | } | |
1361 | ||
1362 | bool JPEGBITSCodec::EncodeBuffer(std::ostream &os, const char *data, size_t datalen) | |
1363 | { | |
1364 | (void)datalen; | |
1365 | JSAMPLE * image_buffer = (JSAMPLE*)data; /* Points to large array of R,G,B-order data */ | |
1366 | const unsigned int *dims = this->GetDimensions(); | |
1367 | int image_height = dims[1]; /* Number of rows in image */ | |
1368 | int image_width = dims[0]; /* Number of columns in image */ | |
1369 | ||
1370 | /* This struct contains the JPEG compression parameters and pointers to | |
1371 | * working space (which is allocated as needed by the JPEG library). | |
1372 | * It is possible to have several such structures, representing multiple | |
1373 | * compression/decompression processes, in existence at once. We refer | |
1374 | * to any one struct (and its associated working data) as a "JPEG object". | |
1375 | */ | |
1376 | jpeg_compress_struct &cinfo = Internals->cinfo_comp; | |
1377 | /* This struct represents a JPEG error handler. It is declared separately | |
1378 | * because applications often want to supply a specialized error handler | |
1379 | * (see the second half of this file for an example). But here we just | |
1380 | * take the easy way out and use the standard error handler, which will | |
1381 | * print a message on stderr and call exit() if compression fails. | |
1382 | * Note that this struct must live as long as the main JPEG parameter | |
1383 | * struct, to avoid dangling-pointer problems. | |
1384 | */ | |
1385 | my_error_mgr &jerr = Internals->jerr; | |
1386 | /* More stuff */ | |
1387 | //FILE * outfile; /* target file */ | |
1388 | std::ostream *outfile = &os; | |
1389 | JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ | |
1390 | size_t row_stride; /* physical row width in image buffer */ | |
1391 | ||
1392 | if( Internals->StateSuspension == 0 ) | |
1393 | { | |
1394 | /* Step 1: allocate and initialize JPEG compression object */ | |
1395 | ||
1396 | /* We have to set up the error handler first, in case the initialization | |
1397 | * step fails. (Unlikely, but it could happen if you are out of memory.) | |
1398 | * This routine fills in the contents of struct jerr, and returns jerr's | |
1399 | * address which we place into the link field in cinfo. | |
1400 | */ | |
1401 | cinfo.err = jpeg_std_error(&jerr.pub); | |
1402 | /* Now we can initialize the JPEG compression object. */ | |
1403 | jpeg_create_compress(&cinfo); | |
1404 | ||
1405 | /* Step 2: specify data destination (eg, a file) */ | |
1406 | /* Note: steps 2 and 3 can be done in either order. */ | |
1407 | ||
1408 | /* Here we use the library-supplied code to send compressed data to a | |
1409 | * stdio stream. You can also write your own code to do something else. | |
1410 | * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that | |
1411 | * requires it in order to write binary files. | |
1412 | */ | |
1413 | //if ((outfile = fopen(filename, "wb")) == NULL) { | |
1414 | // fprintf(stderr, "can't open %s\n", filename); | |
1415 | // exit(1); | |
1416 | //} | |
1417 | } | |
1418 | if( Internals->StateSuspension == 0 ) | |
1419 | { | |
1420 | jpeg_stdio_dest(&cinfo, outfile); | |
1421 | } | |
1422 | ||
1423 | /* Step 3: set parameters for compression */ | |
1424 | ||
1425 | /* First we supply a description of the input image. | |
1426 | * Four fields of the cinfo struct must be filled in: | |
1427 | */ | |
1428 | if( Internals->StateSuspension == 0 ) | |
1429 | { | |
1430 | cinfo.image_width = image_width; /* image width and height, in pixels */ | |
1431 | cinfo.image_height = image_height; | |
1432 | } | |
1433 | ||
1434 | if( Internals->StateSuspension == 0 ) | |
1435 | { | |
1436 | switch( this->GetPhotometricInterpretation() ) | |
1437 | { | |
1438 | case PhotometricInterpretation::MONOCHROME1: | |
1439 | case PhotometricInterpretation::MONOCHROME2: | |
1440 | case PhotometricInterpretation::PALETTE_COLOR: | |
1441 | cinfo.input_components = 1; /* # of color components per pixel */ | |
1442 | cinfo.in_color_space = JCS_GRAYSCALE; /* colorspace of input image */ | |
1443 | break; | |
1444 | case PhotometricInterpretation::RGB: | |
1445 | case PhotometricInterpretation::YBR_RCT: | |
1446 | case PhotometricInterpretation::YBR_ICT: | |
1447 | cinfo.input_components = 3; /* # of color components per pixel */ | |
1448 | cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ | |
1449 | break; | |
1450 | case PhotometricInterpretation::YBR_FULL: | |
1451 | case PhotometricInterpretation::YBR_FULL_422: | |
1452 | case PhotometricInterpretation::YBR_PARTIAL_420: | |
1453 | case PhotometricInterpretation::YBR_PARTIAL_422: | |
1454 | cinfo.input_components = 3; /* # of color components per pixel */ | |
1455 | cinfo.in_color_space = JCS_YCbCr; /* colorspace of input image */ | |
1456 | break; | |
1457 | case PhotometricInterpretation::HSV: | |
1458 | case PhotometricInterpretation::ARGB: | |
1459 | case PhotometricInterpretation::CMYK: | |
1460 | // TODO ! | |
1461 | case PhotometricInterpretation::UNKNOWN: | |
1462 | case PhotometricInterpretation::PI_END: // To please compiler | |
1463 | return false; | |
1464 | } | |
1465 | } | |
1466 | //if ( cinfo.process == JPROC_LOSSLESS ) | |
1467 | // { | |
1468 | // cinfo.in_color_space = JCS_UNKNOWN; | |
1469 | // } | |
1470 | //assert( cinfo.image_height * cinfo.image_width * cinfo.input_components * sizeof(JSAMPLE) == len ); | |
1471 | ||
1472 | /* Now use the library's routine to set default compression parameters. | |
1473 | * (You must set at least cinfo.in_color_space before calling this, | |
1474 | * since the defaults depend on the source color space.) | |
1475 | */ | |
1476 | if( Internals->StateSuspension == 0 ) | |
1477 | { | |
1478 | jpeg_set_defaults(&cinfo); | |
1479 | } | |
1480 | ||
1481 | /* | |
1482 | * predictor = 1 | |
1483 | * point_transform = 0 | |
1484 | * => lossless transformation. | |
1485 | * Basicaly you need to have point_transform = 0, but you can pick whichever predictor [1...7] you want | |
1486 | * TODO: is there a way to pick the right predictor (best compression/fastest ?) | |
1487 | */ | |
1488 | if( Internals->StateSuspension == 0 ) | |
1489 | { | |
1490 | if( !LossyFlag ) | |
1491 | { | |
1492 | jpeg_simple_lossless (&cinfo, 1, 0); | |
1493 | //jpeg_simple_lossless (&cinfo, 7, 0); | |
1494 | } | |
1495 | } | |
1496 | ||
1497 | /* Now you can set any non-default parameters you wish to. | |
1498 | * Here we just illustrate the use of quality (quantization table) scaling: | |
1499 | */ | |
1500 | if( !LossyFlag ) | |
1501 | { | |
1502 | assert( Quality == 100 ); | |
1503 | } | |
1504 | if( Internals->StateSuspension == 0 ) | |
1505 | { | |
1506 | jpeg_set_quality(&cinfo, Quality, TRUE /* limit to baseline-JPEG values */); | |
1507 | } | |
1508 | ||
1509 | if( Internals->StateSuspension == 0 ) | |
1510 | { | |
1511 | /* | |
1512 | * See write_file_header | |
1513 | */ | |
1514 | cinfo.write_JFIF_header = 0; | |
1515 | } | |
1516 | //cinfo.density_unit = 2; | |
1517 | //cinfo.X_density = 2; | |
1518 | //cinfo.Y_density = 5; | |
1519 | ||
1520 | /* Step 4: Start compressor */ | |
1521 | ||
1522 | if( Internals->StateSuspension == 0 ) | |
1523 | { | |
1524 | /* TRUE ensures that we will write a complete interchange-JPEG file. | |
1525 | * Pass TRUE unless you are very sure of what you're doing. | |
1526 | */ | |
1527 | jpeg_start_compress(&cinfo, TRUE); | |
1528 | Internals->StateSuspension = 1; | |
1529 | } | |
1530 | ||
1531 | /* Step 5: while (scan lines remain to be written) */ | |
1532 | /* jpeg_write_scanlines(...); */ | |
1533 | ||
1534 | /* Here we use the library's state variable cinfo.next_scanline as the | |
1535 | * loop counter, so that we don't have to keep track ourselves. | |
1536 | * To keep things simple, we pass one scanline per call; you can pass | |
1537 | * more if you wish, though. | |
1538 | */ | |
1539 | row_stride = image_width * cinfo.input_components; /* JSAMPLEs per row in image_buffer */ | |
1540 | ||
1541 | if ( Internals->StateSuspension == 1 ) | |
1542 | { | |
1543 | assert( this->GetPlanarConfiguration() == 0 ); | |
1544 | assert( row_stride * sizeof(JSAMPLE) == datalen ); | |
1545 | { | |
1546 | //while (cinfo.next_scanline < cinfo.image_height) { | |
1547 | /* jpeg_write_scanlines expects an array of pointers to scanlines. | |
1548 | * Here the array is only one element long, but you could pass | |
1549 | * more than one scanline at a time if that's more convenient. | |
1550 | */ | |
1551 | row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride * 0]; | |
1552 | const JDIMENSION nscanline = jpeg_write_scanlines(&cinfo, row_pointer, 1); | |
1553 | assert( nscanline == 1 ); (void)nscanline; | |
1554 | assert(cinfo.next_scanline <= cinfo.image_height); | |
1555 | //} | |
1556 | } | |
1557 | if(cinfo.next_scanline == cinfo.image_height) | |
1558 | { | |
1559 | Internals->StateSuspension = 2; | |
1560 | } | |
1561 | } | |
1562 | ||
1563 | /* Step 6: Finish compression */ | |
1564 | ||
1565 | if (Internals->StateSuspension == 2 ) | |
1566 | { | |
1567 | jpeg_finish_compress(&cinfo); | |
1568 | /* After finish_compress, we can close the output file. */ | |
1569 | //fclose(outfile); | |
1570 | } | |
1571 | ||
1572 | /* Step 7: release JPEG compression object */ | |
1573 | ||
1574 | if (Internals->StateSuspension == 2 ) | |
1575 | { | |
1576 | /* This is an important step since it will release a good deal of memory. */ | |
1577 | jpeg_destroy_compress(&cinfo); | |
1578 | ||
1579 | Internals->StateSuspension = 0; | |
1580 | } | |
1581 | ||
1582 | /* And we're done! */ | |
1583 | return true; | |
1584 | } | |
1585 | ||
1586 | bool JPEGBITSCodec::IsStateSuspension() const | |
1587 | { | |
1588 | return Internals->StateSuspension != 0; | |
1589 | } | |
1590 | ||
1591 | } // end namespace gdcm |
0 | /*========================================================================= | |
1 | ||
2 | Program: GDCM (Grassroots DICOM). A DICOM library | |
3 | ||
4 | Copyright (c) 2006-2011 Mathieu Malaterre | |
5 | All rights reserved. | |
6 | See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. | |
7 | ||
8 | This software is distributed WITHOUT ANY WARRANTY; without even | |
9 | the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR | |
10 | PURPOSE. See the above copyright notice for more information. | |
11 | ||
12 | =========================================================================*/ | |
13 | #include "gdcmTrace.h" | |
14 | #include "gdcmTransferSyntax.h" | |
15 | ||
16 | #include <limits.h> | |
17 | ||
18 | /* | |
19 | * jdatasrc.c | |
20 | * | |
21 | * Copyright (C) 1994-1996, Thomas G. Lane. | |
22 | * This file is part of the Independent JPEG Group's software. | |
23 | * For conditions of distribution and use, see the accompanying README file. | |
24 | * | |
25 | * This file contains decompression data source routines for the case of | |
26 | * reading JPEG data from a file (or any stdio stream). While these routines | |
27 | * are sufficient for most applications, some will want to use a different | |
28 | * source manager. | |
29 | * IMPORTANT: we assume that fread() will correctly transcribe an array of | |
30 | * JOCTETs from 8-bit-wide elements on external storage. If char is wider | |
31 | * than 8 bits on your machine, you may need to do some tweaking. | |
32 | */ | |
33 | ||
34 | /* this is not a core library module, so it doesn't define JPEG_INTERNALS */ | |
35 | ||
36 | namespace gdcm | |
37 | { | |
38 | ||
39 | /* Expanded data source object for stdio input */ | |
40 | ||
41 | typedef struct { | |
42 | struct jpeg_source_mgr pub; /* public fields */ | |
43 | ||
44 | std::istream * infile; /* source stream */ | |
45 | JOCTET * buffer; /* start of buffer */ | |
46 | boolean start_of_file; /* have we gotten any data yet? */ | |
47 | } my_source_mgr; | |
48 | ||
49 | typedef my_source_mgr * my_src_ptr; | |
50 | ||
51 | #define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */ | |
52 | ||
53 | ||
54 | /* | |
55 | * Initialize source --- called by jpeg_read_header | |
56 | * before any data is actually read. | |
57 | */ | |
58 | ||
59 | METHODDEF(void) | |
60 | init_source (j_decompress_ptr cinfo) | |
61 | { | |
62 | my_src_ptr src = (my_src_ptr) cinfo->src; | |
63 | ||
64 | /* We reset the empty-input-file flag for each image, | |
65 | * but we don't clear the input buffer. | |
66 | * This is correct behavior for reading a series of images from one source. | |
67 | */ | |
68 | src->start_of_file = TRUE; | |
69 | } | |
70 | ||
71 | ||
72 | /* | |
73 | * Fill the input buffer --- called whenever buffer is emptied. | |
74 | * | |
75 | * In typical applications, this should read fresh data into the buffer | |
76 | * (ignoring the current state of next_input_byte & bytes_in_buffer), | |
77 | * reset the pointer & count to the start of the buffer, and return TRUE | |
78 | * indicating that the buffer has been reloaded. It is not necessary to | |
79 | * fill the buffer entirely, only to obtain at least one more byte. | |
80 | * | |
81 | * There is no such thing as an EOF return. If the end of the file has been | |
82 | * reached, the routine has a choice of ERREXIT() or inserting fake data into | |
83 | * the buffer. In most cases, generating a warning message and inserting a | |
84 | * fake EOI marker is the best course of action --- this will allow the | |
85 | * decompressor to output however much of the image is there. However, | |
86 | * the resulting error message is misleading if the real problem is an empty | |
87 | * input file, so we handle that case specially. | |
88 | * | |
89 | * In applications that need to be able to suspend compression due to input | |
90 | * not being available yet, a FALSE return indicates that no more data can be | |
91 | * obtained right now, but more may be forthcoming later. In this situation, | |
92 | * the decompressor will return to its caller (with an indication of the | |
93 | * number of scanlines it has read, if any). The application should resume | |
94 | * decompression after it has loaded more data into the input buffer. Note | |
95 | * that there are substantial restrictions on the use of suspension --- see | |
96 | * the documentation. | |
97 | * | |
98 | * When suspending, the decompressor will back up to a convenient restart point | |
99 | * (typically the start of the current MCU). next_input_byte & bytes_in_buffer | |
100 | * indicate where the restart point will be if the current call returns FALSE. | |
101 | * Data beyond this point must be rescanned after resumption, so move it to | |
102 | * the front of the buffer rather than discarding it. | |
103 | */ | |
104 | ||
105 | METHODDEF(boolean) | |
106 | fill_input_buffer (j_decompress_ptr cinfo) | |
107 | { | |
108 | my_src_ptr src = (my_src_ptr) cinfo->src; | |
109 | size_t nbytes; | |
110 | ||
111 | //FIXME FIXME FIXME FIXME FIXME | |
112 | //nbytes = JFREAD(src->infile, src->buffer, INPUT_BUF_SIZE); | |
113 | std::streampos pos = src->infile->tellg(); | |
114 | std::streampos end = src->infile->seekg(0, std::ios::end).tellg(); | |
115 | src->infile->seekg(pos, std::ios::beg); | |
116 | //FIXME FIXME FIXME FIXME FIXME | |
117 | if( end == pos ) | |
118 | { | |
119 | /* Start the I/O suspension simply by returning false here: */ | |
120 | return FALSE; | |
121 | } | |
122 | if( (end - pos) < INPUT_BUF_SIZE ) | |
123 | { | |
124 | src->infile->read( (char*)src->buffer, (size_t)(end - pos) ); | |
125 | } | |
126 | else | |
127 | { | |
128 | src->infile->read( (char*)src->buffer, INPUT_BUF_SIZE); | |
129 | } | |
130 | ||
131 | std::streamsize gcount = src->infile->gcount(); | |
132 | assert(gcount < INT_MAX); | |
133 | nbytes = (size_t)gcount; | |
134 | ||
135 | if (nbytes <= 0) { | |
136 | if (src->start_of_file) /* Treat empty input file as fatal error */ | |
137 | ERREXIT(cinfo, JERR_INPUT_EMPTY); | |
138 | WARNMS(cinfo, JWRN_JPEG_EOF); | |
139 | /* Insert a fake EOI marker */ | |
140 | src->buffer[0] = (JOCTET) 0xFF; | |
141 | src->buffer[1] = (JOCTET) JPEG_EOI; | |
142 | nbytes = 2; | |
143 | } | |
144 | ||
145 | src->pub.next_input_byte = src->buffer; | |
146 | src->pub.bytes_in_buffer = nbytes; | |
147 | src->start_of_file = FALSE; | |
148 | ||
149 | return TRUE; | |
150 | } | |
151 | ||
152 | ||
153 | /* | |
154 | * Skip data --- used to skip over a potentially large amount of | |
155 | * uninteresting data (such as an APPn marker). | |
156 | * | |
157 | * Writers of suspendable-input applications must note that skip_input_data | |
158 | * is not granted the right to give a suspension return. If the skip extends | |
159 | * beyond the data currently in the buffer, the buffer can be marked empty so | |
160 | * that the next read will cause a fill_input_buffer call that can suspend. | |
161 | * Arranging for additional bytes to be discarded before reloading the input | |
162 | * buffer is the application writer's problem. | |
163 | */ | |
164 | ||
165 | METHODDEF(void) | |
166 | skip_input_data (j_decompress_ptr cinfo, long num_bytes) | |
167 | { | |
168 | my_src_ptr src = (my_src_ptr) cinfo->src; | |
169 | ||
170 | /* Just a dumb implementation for now. Could use fseek() except | |
171 | * it doesn't work on pipes. Not clear that being smart is worth | |
172 | * any trouble anyway --- large skips are infrequent. | |
173 | */ | |
174 | if (num_bytes > 0) { | |
175 | while (num_bytes > (long) src->pub.bytes_in_buffer) { | |
176 | num_bytes -= (long) src->pub.bytes_in_buffer; | |
177 | (void) fill_input_buffer(cinfo); | |
178 | /* note we assume that fill_input_buffer will never return FALSE, | |
179 | * so suspension need not be handled. | |
180 | */ | |
181 | } | |
182 | src->pub.next_input_byte += (size_t) num_bytes; | |
183 | src->pub.bytes_in_buffer -= (size_t) num_bytes; | |
184 | } | |
185 | } | |
186 | ||
187 | ||
188 | /* | |
189 | * An additional method that can be provided by data source modules is the | |
190 | * resync_to_restart method for error recovery in the presence of RST markers. | |
191 | * For the moment, this source module just uses the default resync method | |
192 | * provided by the JPEG library. That method assumes that no backtracking | |
193 | * is possible. | |
194 | */ | |
195 | ||
196 | ||
197 | /* | |
198 | * Terminate source --- called by jpeg_finish_decompress | |
199 | * after all data has been read. Often a no-op. | |
200 | * | |
201 | * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding | |
202 | * application must deal with any cleanup that should happen even | |
203 | * for error exit. | |
204 | */ | |
205 | ||
206 | METHODDEF(void) | |
207 | term_source (j_decompress_ptr cinfo) | |
208 | { | |
209 | (void)cinfo; | |
210 | /* no work necessary here */ | |
211 | } | |
212 | ||
213 | ||
214 | /* | |
215 | * Prepare for input from a stdio stream. | |
216 | * The caller must have already opened the stream, and is responsible | |
217 | * for closing it after finishing decompression. | |
218 | */ | |
219 | ||
220 | GLOBAL(void) | |
221 | jpeg_stdio_src (j_decompress_ptr cinfo, std::istream & infile, bool flag) | |
222 | { | |
223 | my_src_ptr src; | |
224 | ||
225 | /* The source object and input buffer are made permanent so that a series | |
226 | * of JPEG images can be read from the same file by calling jpeg_stdio_src | |
227 | * only before the first one. (If we discarded the buffer at the end of | |
228 | * one image, we'd likely lose the start of the next one.) | |
229 | * This makes it unsafe to use this manager and a different source | |
230 | * manager serially with the same JPEG object. Caveat programmer. | |
231 | */ | |
232 | if (cinfo->src == NULL) { /* first time for this JPEG object? */ | |
233 | cinfo->src = (struct jpeg_source_mgr *) | |
234 | (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, | |
235 | SIZEOF(my_source_mgr)); | |
236 | src = (my_src_ptr) cinfo->src; | |
237 | src->buffer = (JOCTET *) | |
238 | (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, | |
239 | INPUT_BUF_SIZE * SIZEOF(JOCTET)); | |
240 | } | |
241 | ||
242 | src = (my_src_ptr) cinfo->src; | |
243 | src->pub.init_source = init_source; | |
244 | src->pub.fill_input_buffer = fill_input_buffer; | |
245 | src->pub.skip_input_data = skip_input_data; | |
246 | src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ | |
247 | src->pub.term_source = term_source; | |
248 | src->infile = &infile; | |
249 | if( flag ) | |
250 | { | |
251 | src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ | |
252 | src->pub.next_input_byte = NULL; /* until buffer loaded */ | |
253 | } | |
254 | } | |
255 | ||
256 | } // end namespace gdcm | |
257 | ||
258 | ||
259 | namespace gdcm | |
260 | { | |
261 | /* | |
262 | * The following was copy/paste from example.c | |
263 | */ | |
264 | ||
265 | struct my_error_mgr { | |
266 | struct jpeg_error_mgr pub; /* "public" fields */ | |
267 | jmp_buf setjmp_buffer; /* for return to caller */ | |
268 | }; | |
269 | typedef struct my_error_mgr* my_error_ptr; | |
270 | ||
271 | class JPEGInternals | |
272 | { | |
273 | public: | |
274 | JPEGInternals():cinfo(),jerr(),StateSuspension(0),SampBuffer(0) {} | |
275 | jpeg_decompress_struct cinfo; | |
276 | jpeg_compress_struct cinfo_comp; | |
277 | my_error_mgr jerr; | |
278 | int StateSuspension; | |
279 | void *SampBuffer; | |
280 | }; | |
281 | ||
282 | JPEGBITSCodec::JPEGBITSCodec() | |
283 | { | |
284 | Internals = new JPEGInternals; | |
285 | BitSample = BITS_IN_JSAMPLE; | |
286 | } | |
287 | ||
288 | JPEGBITSCodec::~JPEGBITSCodec() | |
289 | { | |
290 | delete Internals; | |
291 | } | |
292 | ||
293 | /* | |
294 | * Here's the routine that will replace the standard error_exit method: | |
295 | */ | |
296 | extern "C" { | |
297 | METHODDEF(void) my_error_exit (j_common_ptr cinfo) { | |
298 | /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */ | |
299 | my_error_ptr myerr = (my_error_ptr) cinfo->err; | |
300 | ||
301 | /* Always display the message. */ | |
302 | /* We could postpone this until after returning, if we chose. */ | |
303 | (*cinfo->err->output_message) (cinfo); | |
304 | ||
305 | /* Return control to the setjmp point */ | |
306 | longjmp(myerr->setjmp_buffer, 1); | |
307 | } | |
308 | } | |
309 | ||
310 | bool JPEGBITSCodec::GetHeaderInfo(std::istream &is, TransferSyntax &ts) | |
311 | { | |
312 | /* This struct contains the JPEG decompression parameters and pointers to | |
313 | * working space (which is allocated as needed by the JPEG library). | |
314 | */ | |
315 | jpeg_decompress_struct &cinfo = Internals->cinfo; | |
316 | ||
317 | /* We use our private extension JPEG error handler. | |
318 | * Note that this struct must live as long as the main JPEG parameter | |
319 | * struct, to avoid dangling-pointer problems. | |
320 | */ | |
321 | my_error_mgr &jerr = Internals->jerr; | |
322 | /* More stuff */ | |
323 | //FILE * infile; /* source file */ | |
324 | //JSAMPARRAY buffer; /* Output row buffer */ | |
325 | //int row_stride; /* physical row width in output buffer */ | |
326 | ||
327 | if( Internals->StateSuspension == 0 ) | |
328 | { | |
329 | // Step 1: allocate and initialize JPEG decompression object | |
330 | // | |
331 | // We set up the normal JPEG error routines, then override error_exit. | |
332 | cinfo.err = jpeg_std_error(&jerr.pub); | |
333 | jerr.pub.error_exit = my_error_exit; | |
334 | // Establish the setjmp return context for my_error_exit to use. | |
335 | if (setjmp(jerr.setjmp_buffer)) | |
336 | { | |
337 | // If we get here, the JPEG code has signaled an error. | |
338 | // We need to clean up the JPEG object, close the input file, and return. | |
339 | // But first handle the case IJG does not like: | |
340 | if ( jerr.pub.msg_code == JERR_BAD_PRECISION /* 18 */ ) | |
341 | { | |
342 | this->BitSample = jerr.pub.msg_parm.i[0]; | |
343 | assert( this->BitSample == 1 || this->BitSample == 8 || this->BitSample == 12 || this->BitSample == 16 ); | |
344 | assert( this->BitSample == cinfo.data_precision ); | |
345 | } | |
346 | jpeg_destroy_decompress(&cinfo); | |
347 | // TODO: www.dcm4che.org/jira/secure/attachment/10185/ct-implicit-little.dcm | |
348 | // weird Icon Image from GE... | |
349 | return false; | |
350 | } | |
351 | } | |
352 | ||
353 | if( Internals->StateSuspension == 0 ) | |
354 | { | |
355 | // Now we can initialize the JPEG decompression object. | |
356 | jpeg_create_decompress(&cinfo); | |
357 | ||
358 | // Step 2: specify data source (eg, a file) | |
359 | jpeg_stdio_src(&cinfo, is, true); | |
360 | } | |
361 | else | |
362 | { | |
363 | jpeg_stdio_src(&cinfo, is, false); | |
364 | } | |
365 | ||
366 | /* Step 3: read file parameters with jpeg_read_header() */ | |
367 | ||
368 | if ( Internals->StateSuspension < 2 ) | |
369 | { | |
370 | if( jpeg_read_header(&cinfo, TRUE) == JPEG_SUSPENDED ) | |
371 | { | |
372 | Internals->StateSuspension = 2; | |
373 | } | |
374 | // First of all are we using the proper JPEG decoder (correct bit sample): | |
375 | if( jerr.pub.num_warnings ) | |
376 | { | |
377 | if ( jerr.pub.msg_code == 128 ) | |
378 | { | |
379 | this->BitSample = jerr.pub.msg_parm.i[0]; | |
380 | jpeg_destroy_decompress(&cinfo); | |
381 | return false; | |
382 | } | |
383 | else | |
384 | { | |
385 | assert( 0 ); | |
386 | } | |
387 | } | |
388 | this->Dimensions[1] = cinfo.image_height; /* Number of rows in image */ | |
389 | this->Dimensions[0] = cinfo.image_width; /* Number of columns in image */ | |
390 | ||
391 | int prep = this->PF.GetPixelRepresentation(); | |
392 | //this->BitSample = cinfo.data_precision; | |
393 | int precision = cinfo.data_precision; | |
394 | // if lossy it should only be 8 or 12, but for lossless it can be [2-16] | |
395 | if( precision == 1 ) | |
396 | { | |
397 | // lossless ! | |
398 | this->PF = PixelFormat( PixelFormat::SINGLEBIT ); | |
399 | } | |
400 | else if( precision <= 8 ) | |
401 | { | |
402 | this->PF = PixelFormat( PixelFormat::UINT8 ); | |
403 | } | |
404 | else if( precision <= 12 ) | |
405 | { | |
406 | this->PF = PixelFormat( PixelFormat::UINT12 ); | |
407 | } | |
408 | else if( precision <= 16 ) | |
409 | { | |
410 | // lossless ! | |
411 | this->PF = PixelFormat( PixelFormat::UINT16 ); | |
412 | } | |
413 | else | |
414 | { | |
415 | assert( 0 ); | |
416 | } | |
417 | this->PF.SetPixelRepresentation( (uint16_t)prep ); | |
418 | this->PF.SetBitsStored( (uint16_t)precision ); | |
419 | assert( (precision - 1) >= 0 ); | |
420 | this->PF.SetHighBit( (uint16_t)(precision - 1) ); | |
421 | ||
422 | this->PlanarConfiguration = 0; | |
423 | // Let's check the color space: | |
424 | // JCS_UNKNOWN -> 0 | |
425 | // JCS_GRAYSCALE, /* monochrome */ | |
426 | // JCS_RGB, /* red/green/blue */ | |
427 | // JCS_YCbCr, /* Y/Cb/Cr (also known as YUV) */ | |
428 | // JCS_CMYK, /* C/M/Y/K */ | |
429 | // JCS_YCCK /* Y/Cb/Cr/K */ | |
430 | ||
431 | if( cinfo.jpeg_color_space == JCS_UNKNOWN ) | |
432 | { | |
433 | // I do not know if this possible, it looks like IJG always computes a default | |
434 | if( cinfo.num_components == 1 ) | |
435 | { | |
436 | PI = PhotometricInterpretation::MONOCHROME2; | |
437 | this->PF.SetSamplesPerPixel( 1 ); | |
438 | } | |
439 | else if( cinfo.num_components == 3 ) | |
440 | { | |
441 | PI = PhotometricInterpretation::RGB; | |
442 | this->PF.SetSamplesPerPixel( 3 ); | |
443 | } | |
444 | else | |
445 | { | |
446 | assert( 0 ); | |
447 | } | |
448 | } | |
449 | else if( cinfo.jpeg_color_space == JCS_GRAYSCALE ) | |
450 | { | |
451 | assert( cinfo.num_components == 1 ); | |
452 | PI = PhotometricInterpretation::MONOCHROME2; | |
453 | this->PF.SetSamplesPerPixel( 1 ); | |
454 | } | |
455 | else if( cinfo.jpeg_color_space == JCS_RGB ) | |
456 | { | |
457 | assert( cinfo.num_components == 3 ); | |
458 | PI = PhotometricInterpretation::RGB; | |
459 | this->PF.SetSamplesPerPixel( 3 ); | |
460 | } | |
461 | else if( cinfo.jpeg_color_space == JCS_YCbCr ) | |
462 | { | |
463 | assert( cinfo.num_components == 3 ); | |
464 | PI = PhotometricInterpretation::YBR_FULL_422; | |
465 | if( cinfo.process == JPROC_LOSSLESS ) | |
466 | PI = PhotometricInterpretation::RGB; // wotsit ? | |
467 | this->PF.SetSamplesPerPixel( 3 ); | |
468 | this->PlanarConfiguration = 1; | |
469 | } | |
470 | else if( cinfo.jpeg_color_space == JCS_CMYK ) | |
471 | { | |
472 | assert( cinfo.num_components == 4 ); | |
473 | PI = PhotometricInterpretation::CMYK; | |
474 | this->PF.SetSamplesPerPixel( 4 ); | |
475 | } | |
476 | else if( cinfo.jpeg_color_space == JCS_YCCK ) | |
477 | { | |
478 | assert( cinfo.num_components == 4 ); | |
479 | PI = PhotometricInterpretation::YBR_FULL_422; // 4th plane ?? | |
480 | this->PF.SetSamplesPerPixel( 4 ); | |
481 | assert( 0 ); //TODO | |
482 | } | |
483 | else | |
484 | { | |
485 | assert( 0 ); //TODO | |
486 | } | |
487 | } | |
488 | if( cinfo.process == JPROC_LOSSLESS ) | |
489 | { | |
490 | int predictor = cinfo.Ss; | |
491 | /* not very user friendly... */ | |
492 | switch(predictor) | |
493 | { | |
494 | case 1: | |
495 | ts = TransferSyntax::JPEGLosslessProcess14_1; | |
496 | break; | |
497 | default: | |
498 | ts = TransferSyntax::JPEGLosslessProcess14; | |
499 | break; | |
500 | } | |
501 | } | |
502 | else if( cinfo.process == JPROC_SEQUENTIAL ) | |
503 | { | |
504 | if( this->BitSample == 8 ) | |
505 | ts = TransferSyntax::JPEGBaselineProcess1; | |
506 | else if( this->BitSample == 12 ) | |
507 | ts = TransferSyntax::JPEGExtendedProcess2_4; | |
508 | } | |
509 | else if( cinfo.process == JPROC_PROGRESSIVE ) | |
510 | { | |
511 | if( this->BitSample == 8 ) | |
512 | { | |
513 | ts = TransferSyntax::JPEGFullProgressionProcess10_12; | |
514 | } | |
515 | else if( this->BitSample == 12 ) | |
516 | { | |
517 | ts = TransferSyntax::JPEGFullProgressionProcess10_12; | |
518 | } | |
519 | else | |
520 | { | |
521 | assert(0); // TODO | |
522 | return false; | |
523 | } | |
524 | } | |
525 | else | |
526 | { | |
527 | assert(0); // TODO | |
528 | return false; | |
529 | } | |
530 | if( cinfo.process == JPROC_LOSSLESS ) | |
531 | { | |
532 | LossyFlag = false; | |
533 | } | |
534 | else | |
535 | { | |
536 | LossyFlag = true; | |
537 | } | |
538 | ||
539 | // Pixel density stuff: | |
540 | /* | |
541 | UINT8 density_unit | |
542 | UINT16 X_density | |
543 | UINT16 Y_density | |
544 | The resolution information to be written into the JFIF marker; | |
545 | not used otherwise. density_unit may be 0 for unknown, | |
546 | 1 for dots/inch, or 2 for dots/cm. The default values are 0,1,1 | |
547 | indicating square pixels of unknown size. | |
548 | */ | |
549 | ||
550 | if( cinfo.density_unit != 0 | |
551 | || cinfo.X_density != 1 | |
552 | || cinfo.Y_density != 1 | |
553 | ) | |
554 | { | |
555 | gdcmWarningMacro( "Pixel Density from JFIF Marker is not supported (for now)" ); | |
556 | //return false; | |
557 | } | |
558 | ||
559 | ||
560 | #if 0 | |
561 | switch ( cinfo.jpeg_color_space ) | |
562 | { | |
563 | case JCS_GRAYSCALE: | |
564 | if( GetPhotometricInterpretation() != PhotometricInterpretation::MONOCHROME1 | |
565 | && GetPhotometricInterpretation() != PhotometricInterpretation::MONOCHROME2 ) | |
566 | { | |
567 | gdcmWarningMacro( "Wrong PhotometricInterpretation. DICOM says: " << | |
568 | GetPhotometricInterpretation() << " but JPEG says: " | |
569 | << cinfo.jpeg_color_space ); | |
570 | //Internals->SetPhotometricInterpretation( PhotometricInterpretation::MONOCHROME2 ); | |
571 | this->PI = PhotometricInterpretation::MONOCHROME2; | |
572 | } | |
573 | break; | |
574 | case JCS_RGB: | |
575 | assert( GetPhotometricInterpretation() == PhotometricInterpretation::RGB ); | |
576 | break; | |
577 | case JCS_YCbCr: | |
578 | if( GetPhotometricInterpretation() != PhotometricInterpretation::YBR_FULL && | |
579 | GetPhotometricInterpretation() != PhotometricInterpretation::YBR_FULL_422 ) | |
580 | { | |
581 | // DermaColorLossLess.dcm (lossless) | |
582 | // LEADTOOLS_FLOWERS-24-RGB-JpegLossy.dcm (lossy) | |
583 | gdcmWarningMacro( "Wrong PhotometricInterpretation. DICOM says: " << | |
584 | GetPhotometricInterpretation() << " but JPEG says: " | |
585 | << cinfo.jpeg_color_space ); | |
586 | // Here it gets nasty since apparently when this occurs lossless means | |
587 | // we should not do any color conversion, but we *might* be breaking | |
588 | // correct DICOM file. | |
589 | // FIXME FIXME | |
590 | /* prevent the library from performing any color space conversion */ | |
591 | if ( cinfo.process == JPROC_LOSSLESS ) | |
592 | { | |
593 | cinfo.jpeg_color_space = JCS_UNKNOWN; | |
594 | cinfo.out_color_space = JCS_UNKNOWN; | |
595 | } | |
596 | } | |
597 | break; | |
598 | default: | |
599 | assert(0); | |
600 | return false; | |
601 | } | |
602 | //assert( cinfo.data_precision == BITS_IN_JSAMPLE ); | |
603 | //assert( cinfo.data_precision == this->BitSample ); | |
604 | ||
605 | /* Step 4: set parameters for decompression */ | |
606 | /* no op */ | |
607 | } | |
608 | ||
609 | /* Step 5: Start decompressor */ | |
610 | ||
611 | if (Internals->StateSuspension < 3 ) | |
612 | { | |
613 | if ( jpeg_start_decompress(&cinfo) == FALSE ) | |
614 | { | |
615 | /* Suspension: jpeg_start_decompress */ | |
616 | Internals->StateSuspension = 3; | |
617 | } | |
618 | ||
619 | /* We may need to do some setup of our own at this point before reading | |
620 | * the data. After jpeg_start_decompress() we have the correct scaled | |
621 | * output image dimensions available, as well as the output colormap | |
622 | * if we asked for color quantization. | |
623 | * In this example, we need to make an output work buffer of the right size. | |
624 | */ | |
625 | /* JSAMPLEs per row in output buffer */ | |
626 | row_stride = cinfo.output_width * cinfo.output_components; | |
627 | row_stride *= sizeof(JSAMPLE); | |
628 | /* Make a one-row-high sample array that will go away when done with image */ | |
629 | buffer = (*cinfo.mem->alloc_sarray) | |
630 | ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); | |
631 | ||
632 | /* Save the buffer in case of suspension to be able to reuse it later: */ | |
633 | Internals->SampBuffer = buffer; | |
634 | } | |
635 | else | |
636 | { | |
637 | /* JSAMPLEs per row in output buffer */ | |
638 | row_stride = cinfo.output_width * cinfo.output_components; | |
639 | row_stride *= sizeof(JSAMPLE); | |
640 | ||
641 | /* Suspension: re-use the buffer: */ | |
642 | buffer = (JSAMPARRAY)Internals->SampBuffer; | |
643 | } | |
644 | ||
645 | /* Step 6: while (scan lines remain to be read) */ | |
646 | /* jpeg_read_scanlines(...); */ | |
647 | ||
648 | /* Here we use the library's state variable cinfo.output_scanline as the | |
649 | * loop counter, so that we don't have to keep track ourselves. | |
650 | */ | |
651 | while (cinfo.output_scanline < cinfo.output_height) { | |
652 | /* jpeg_read_scanlines expects an array of pointers to scanlines. | |
653 | * Here the array is only one element long, but you could ask for | |
654 | * more than one scanline at a time if that's more convenient. | |
655 | */ | |
656 | if( jpeg_read_scanlines(&cinfo, buffer, 1) == 0 ) | |
657 | { | |
658 | /* Suspension in jpeg_read_scanlines */ | |
659 | Internals->StateSuspension = 3; | |
660 | return true; | |
661 | } | |
662 | os.write((char*)buffer[0], row_stride); | |
663 | } | |
664 | ||
665 | /* Step 7: Finish decompression */ | |
666 | ||
667 | if( jpeg_finish_decompress(&cinfo) == FALSE ) | |
668 | { | |
669 | /* Suspension: jpeg_finish_decompress */ | |
670 | Internals->StateSuspension = 4; | |
671 | } | |
672 | #endif | |
673 | ||
674 | /* Step 8: Release JPEG decompression object */ | |
675 | ||
676 | /* This is an important step since it will release a good deal of memory. */ | |
677 | jpeg_destroy_decompress(&cinfo); | |
678 | ||
679 | /* After finish_decompress, we can close the input file. | |
680 | * Here we postpone it until after no more JPEG errors are possible, | |
681 | * so as to simplify the setjmp error logic above. (Actually, I don't | |
682 | * think that jpeg_destroy can do an error exit, but why assume anything...) | |
683 | */ | |
684 | //fclose(infile); | |
685 | ||
686 | /* At this point you may want to check to see whether any corrupt-data | |
687 | * warnings occurred (test whether jerr.pub.num_warnings is nonzero). | |
688 | */ | |
689 | /* In any case make sure the we reset the internal state suspension */ | |
690 | Internals->StateSuspension = 0; | |
691 | ||
692 | /* And we're done! */ | |
693 | return true; | |
694 | ||
695 | } | |
696 | ||
697 | /* | |
698 | * Note: see dcmdjpeg +cn option to avoid the YBR => RGB loss | |
699 | */ | |
700 | bool JPEGBITSCodec::DecodeByStreams(std::istream &is, std::ostream &os) | |
701 | { | |
702 | /* This struct contains the JPEG decompression parameters and pointers to | |
703 | * working space (which is allocated as needed by the JPEG library). | |
704 | */ | |
705 | jpeg_decompress_struct &cinfo = Internals->cinfo; | |
706 | ||
707 | /* We use our private extension JPEG error handler. | |
708 | * Note that this struct must live as long as the main JPEG parameter | |
709 | * struct, to avoid dangling-pointer problems. | |
710 | */ | |
711 | my_error_mgr &jerr = Internals->jerr; | |
712 | /* More stuff */ | |
713 | //FILE * infile; /* source file */ | |
714 | JSAMPARRAY buffer; /* Output row buffer */ | |
715 | size_t row_stride; /* physical row width in output buffer */ | |
716 | ||
717 | if( Internals->StateSuspension == 0 ) | |
718 | { | |
719 | // Step 1: allocate and initialize JPEG decompression object | |
720 | // | |
721 | // We set up the normal JPEG error routines, then override error_exit. | |
722 | cinfo.err = jpeg_std_error(&jerr.pub); | |
723 | jerr.pub.error_exit = my_error_exit; | |
724 | // Establish the setjmp return context for my_error_exit to use. | |
725 | if (setjmp(jerr.setjmp_buffer)) | |
726 | { | |
727 | // If we get here, the JPEG code has signaled an error. | |
728 | // We need to clean up the JPEG object, close the input file, and return. | |
729 | // But first handle the case IJG does not like: | |
730 | if ( jerr.pub.msg_code == JERR_BAD_PRECISION /* 18 */ ) | |
731 | { | |
732 | this->BitSample = jerr.pub.msg_parm.i[0]; | |
733 | //assert( this->BitSample == 8 || this->BitSample == 12 || this->BitSample == 16 ); | |
734 | } | |
735 | jpeg_destroy_decompress(&cinfo); | |
736 | // TODO: www.dcm4che.org/jira/secure/attachment/10185/ct-implicit-little.dcm | |
737 | // weird Icon Image from GE... | |
738 | return false; | |
739 | } | |
740 | } | |
741 | ||
742 | if( Internals->StateSuspension == 0 ) | |
743 | { | |
744 | // Now we can initialize the JPEG decompression object. | |
745 | jpeg_create_decompress(&cinfo); | |
746 | ||
747 | // Step 2: specify data source (eg, a file) | |
748 | jpeg_stdio_src(&cinfo, is, true); | |
749 | } | |
750 | else | |
751 | { | |
752 | jpeg_stdio_src(&cinfo, is, false); | |
753 | } | |
754 | ||
755 | /* Step 3: read file parameters with jpeg_read_header() */ | |
756 | ||
757 | if ( Internals->StateSuspension < 2 ) | |
758 | { | |
759 | if( jpeg_read_header(&cinfo, TRUE) == JPEG_SUSPENDED ) | |
760 | { | |
761 | Internals->StateSuspension = 2; | |
762 | } | |
763 | // First of all are we using the proper JPEG decoder (correct bit sample): | |
764 | if( jerr.pub.num_warnings ) | |
765 | { | |
766 | // PHILIPS_Gyroscan-12-MONO2-Jpeg_Lossless.dcm | |
767 | if ( jerr.pub.msg_code == JWRN_MUST_DOWNSCALE ) | |
768 | { | |
769 | // PHILIPS_Gyroscan-12-Jpeg_Extended_Process_2_4.dcm | |
770 | // PHILIPS_Gyroscan-12-MONO2-Jpeg_Lossless.dcm | |
771 | // MARCONI_MxTWin-12-MONO2-JpegLossless-ZeroLengthSQ.dcm | |
772 | // LJPEG_BuginGDCM12.dcm | |
773 | gdcmDebugMacro( "JWRN_MUST_DOWNSCALE" ); | |
774 | this->BitSample = jerr.pub.msg_parm.i[0]; | |
775 | assert( cinfo.data_precision == this->BitSample ); | |
776 | jpeg_destroy_decompress(&cinfo); | |
777 | return false; | |
778 | } | |
779 | else | |
780 | { | |
781 | assert( 0 ); | |
782 | } | |
783 | } | |
784 | // Let's check the color space: | |
785 | // JCS_UNKNOWN -> 0 | |
786 | // JCS_GRAYSCALE | |
787 | // JCS_RGB | |
788 | // JCS_YCbCr | |
789 | // JCS_CMYK | |
790 | // JCS_YCCK | |
791 | ||
792 | // Sanity checks: | |
793 | const unsigned int * dims = this->GetDimensions(); | |
794 | if( cinfo.image_width != dims[0] | |
795 | || cinfo.image_height != dims[1] ) | |
796 | { | |
797 | gdcmWarningMacro( "dimension mismatch. JPEG is " << | |
798 | cinfo.image_width << "," << cinfo.image_height << " while DICOM " << dims[0] << | |
799 | "," << dims[1] ); | |
800 | //this->Dimensions[0] = cinfo.image_width; | |
801 | //this->Dimensions[1] = cinfo.image_height; | |
802 | /* | |
803 | * Long story short, the real issue is that class such as ImageRegionReader expect to read the | |
804 | * image information without ever touching the JPEG codestream... | |
805 | */ | |
806 | return false; | |
807 | } | |
808 | assert( cinfo.image_width == dims[0] ); | |
809 | assert( cinfo.image_height == dims[1] ); | |
810 | ||
811 | switch ( cinfo.jpeg_color_space ) | |
812 | { | |
813 | case JCS_GRAYSCALE: | |
814 | if( GetPhotometricInterpretation() != PhotometricInterpretation::MONOCHROME1 | |
815 | && GetPhotometricInterpretation() != PhotometricInterpretation::MONOCHROME2 ) | |
816 | { | |
817 | gdcmWarningMacro( "Wrong PhotometricInterpretation. DICOM says: " << | |
818 | GetPhotometricInterpretation() << " but JPEG says: " | |
819 | << (int)cinfo.jpeg_color_space ); | |
820 | //Internals->SetPhotometricInterpretation( PhotometricInterpretation::MONOCHROME2 ); | |
821 | this->PI = PhotometricInterpretation::MONOCHROME2; | |
822 | } | |
823 | break; | |
824 | case JCS_RGB: | |
825 | //assert( GetPhotometricInterpretation() == PhotometricInterpretation::RGB ); | |
826 | if ( cinfo.process == JPROC_LOSSLESS ) | |
827 | { | |
828 | cinfo.jpeg_color_space = JCS_UNKNOWN; | |
829 | cinfo.out_color_space = JCS_UNKNOWN; | |
830 | } | |
831 | if( GetPhotometricInterpretation() == PhotometricInterpretation::YBR_RCT | |
832 | || GetPhotometricInterpretation() == PhotometricInterpretation::YBR_ICT ) | |
833 | this->PI = PhotometricInterpretation::RGB; | |
834 | break; | |
835 | case JCS_YCbCr: | |
836 | if( GetPhotometricInterpretation() != PhotometricInterpretation::YBR_FULL && | |
837 | GetPhotometricInterpretation() != PhotometricInterpretation::YBR_FULL_422 ) | |
838 | { | |
839 | // DermaColorLossLess.dcm (lossless) | |
840 | // LEADTOOLS_FLOWERS-24-RGB-JpegLossy.dcm (lossy) | |
841 | gdcmWarningMacro( "Wrong PhotometricInterpretation. DICOM says: " << | |
842 | GetPhotometricInterpretation() << " but JPEG says: " | |
843 | << (int)cinfo.jpeg_color_space ); | |
844 | // Here it gets nasty since apparently when this occurs lossless means | |
845 | // we should not do any color conversion, but we *might* be breaking | |
846 | // correct DICOM file. | |
847 | // FIXME FIXME | |
848 | /* prevent the library from performing any color space conversion */ | |
849 | cinfo.jpeg_color_space = JCS_UNKNOWN; | |
850 | cinfo.out_color_space = JCS_UNKNOWN; | |
851 | } | |
852 | if ( cinfo.process == JPROC_LOSSLESS ) | |
853 | { | |
854 | //cinfo.jpeg_color_space = JCS_UNKNOWN; | |
855 | //cinfo.out_color_space = JCS_UNKNOWN; | |
856 | } | |
857 | if( GetPhotometricInterpretation() == PhotometricInterpretation::YBR_FULL | |
858 | || GetPhotometricInterpretation() == PhotometricInterpretation::YBR_FULL_422 ) | |
859 | { | |
860 | cinfo.jpeg_color_space = JCS_UNKNOWN; | |
861 | cinfo.out_color_space = JCS_UNKNOWN; | |
862 | //this->PlanarConfiguration = 1; | |
863 | } | |
864 | break; | |
865 | case JCS_CMYK: | |
866 | assert( GetPhotometricInterpretation() == PhotometricInterpretation::CMYK ); | |
867 | if ( cinfo.process == JPROC_LOSSLESS ) | |
868 | { | |
869 | cinfo.jpeg_color_space = JCS_UNKNOWN; | |
870 | cinfo.out_color_space = JCS_UNKNOWN; | |
871 | } | |
872 | break; | |
873 | case JCS_UNKNOWN: | |
874 | if ( cinfo.process == JPROC_LOSSLESS ) | |
875 | { | |
876 | cinfo.jpeg_color_space = JCS_UNKNOWN; | |
877 | cinfo.out_color_space = JCS_UNKNOWN; | |
878 | } | |
879 | break; | |
880 | default: | |
881 | assert(0); | |
882 | return false; | |
883 | } | |
884 | //assert( cinfo.data_precision == BITS_IN_JSAMPLE ); | |
885 | //assert( cinfo.data_precision == this->BitSample ); | |
886 | ||
887 | /* Step 4: set parameters for decompression */ | |
888 | /* no op */ | |
889 | } | |
890 | ||
891 | /* Step 5: Start decompressor */ | |
892 | ||
893 | if (Internals->StateSuspension < 3 ) | |
894 | { | |
895 | if ( jpeg_start_decompress(&cinfo) == FALSE ) | |
896 | { | |
897 | /* Suspension: jpeg_start_decompress */ | |
898 | Internals->StateSuspension = 3; | |
899 | } | |
900 | ||
901 | /* We may need to do some setup of our own at this point before reading | |
902 | * the data. After jpeg_start_decompress() we have the correct scaled | |
903 | * output image dimensions available, as well as the output colormap | |
904 | * if we asked for color quantization. | |
905 | * In this example, we need to make an output work buffer of the right size. | |
906 | */ | |
907 | /* JSAMPLEs per row in output buffer */ | |
908 | row_stride = cinfo.output_width * cinfo.output_components; | |
909 | row_stride *= sizeof(JSAMPLE); | |
910 | /* Make a one-row-high sample array that will go away when done with image */ | |
911 | buffer = (*cinfo.mem->alloc_sarray) | |
912 | ((j_common_ptr) &cinfo, JPOOL_IMAGE, (JDIMENSION)row_stride, 1); | |
913 | ||
914 | /* Save the buffer in case of suspension to be able to reuse it later: */ | |
915 | Internals->SampBuffer = buffer; | |
916 | } | |
917 | else | |
918 | { | |
919 | /* JSAMPLEs per row in output buffer */ | |
920 | row_stride = cinfo.output_width * cinfo.output_components; | |
921 | row_stride *= sizeof(JSAMPLE); | |
922 | ||
923 | /* Suspension: re-use the buffer: */ | |
924 | buffer = (JSAMPARRAY)Internals->SampBuffer; | |
925 | } | |
926 | ||
927 | /* Step 6: while (scan lines remain to be read) */ | |
928 | /* jpeg_read_scanlines(...); */ | |
929 | ||
930 | /* Here we use the library's state variable cinfo.output_scanline as the | |
931 | * loop counter, so that we don't have to keep track ourselves. | |
932 | */ | |
933 | while (cinfo.output_scanline < cinfo.output_height) { | |
934 | /* jpeg_read_scanlines expects an array of pointers to scanlines. | |
935 | * Here the array is only one element long, but you could ask for | |
936 | * more than one scanline at a time if that's more convenient. | |
937 | */ | |
938 | if( jpeg_read_scanlines(&cinfo, buffer, 1) == 0 ) | |
939 | { | |
940 | /* Suspension in jpeg_read_scanlines */ | |
941 | Internals->StateSuspension = 3; | |
942 | return true; | |
943 | } | |
944 | os.write((char*)buffer[0], row_stride); | |
945 | } | |
946 | ||
947 | /* Step 7: Finish decompression */ | |
948 | ||
949 | if( jpeg_finish_decompress(&cinfo) == FALSE ) | |
950 | { | |
951 | /* Suspension: jpeg_finish_decompress */ | |
952 | Internals->StateSuspension = 4; | |
953 | return true; | |
954 | } | |
955 | ||
956 | /* we are done decompressing the file, now is a good time to store the type | |
957 | of compression used: lossless or not */ | |
958 | if( cinfo.process == JPROC_LOSSLESS ) | |
959 | { | |
960 | LossyFlag = false; | |
961 | } | |
962 | else | |
963 | { | |
964 | LossyFlag = true; | |
965 | } | |
966 | ||
967 | /* Step 8: Release JPEG decompression object */ | |
968 | ||
969 | /* This is an important step since it will release a good deal of memory. */ | |
970 | jpeg_destroy_decompress(&cinfo); | |
971 | ||
972 | /* After finish_decompress, we can close the input file. | |
973 | * Here we postpone it until after no more JPEG errors are possible, | |
974 | * so as to simplify the setjmp error logic above. (Actually, I don't | |
975 | * think that jpeg_destroy can do an error exit, but why assume anything...) | |
976 | */ | |
977 | //fclose(infile); | |
978 | ||
979 | /* At this point you may want to check to see whether any corrupt-data | |
980 | * warnings occurred (test whether jerr.pub.num_warnings is nonzero). | |
981 | */ | |
982 | /* gdcmData/D_CLUNIE_MR4_JPLY.dcm produces a single warning: | |
983 | * Invalid SOS parameters for sequential JPEG | |
984 | * Be nice with this one: | |
985 | */ | |
986 | if( jerr.pub.num_warnings > 1 ) | |
987 | { | |
988 | gdcmErrorMacro( "Too many warning during decompression of JPEG stream: " << jerr.pub.num_warnings ); | |
989 | return false; | |
990 | } | |
991 | /* In any case make sure the we reset the internal state suspension */ | |
992 | Internals->StateSuspension = 0; | |
993 | ||
994 | /* And we're done! */ | |
995 | return true; | |
996 | } | |
997 | ||
998 | /* | |
999 | * jdatadst.c | |
1000 | * | |
1001 | * Copyright (C) 1994-1996, Thomas G. Lane. | |
1002 | * This file is part of the Independent JPEG Group's software. | |
1003 | * For conditions of distribution and use, see the accompanying README file. | |
1004 | * | |
1005 | * This file contains compression data destination routines for the case of | |
1006 | * emitting JPEG data to a file (or any stdio stream). While these routines | |
1007 | * are sufficient for most applications, some will want to use a different | |
1008 | * destination manager. | |
1009 | * IMPORTANT: we assume that fwrite() will correctly transcribe an array of | |
1010 | * JOCTETs into 8-bit-wide elements on external storage. If char is wider | |
1011 | * than 8 bits on your machine, you may need to do some tweaking. | |
1012 | */ | |
1013 | ||
1014 | /** | |
1015 | * \brief very low level C 'structure', used to decode jpeg file | |
1016 | * Should not appear in the Doxygen supplied documentation | |
1017 | */ | |
1018 | typedef struct { | |
1019 | struct jpeg_destination_mgr pub; /* public fields */ | |
1020 | ||
1021 | std::ostream * outfile; /* target stream */ | |
1022 | JOCTET * buffer; /* start of buffer */ | |
1023 | } my_destination_mgr; | |
1024 | ||
1025 | typedef my_destination_mgr * my_dest_ptr; | |
1026 | ||
1027 | #define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */ | |
1028 | ||
1029 | /* | |
1030 | * Initialize destination --- called by jpeg_start_compress | |
1031 | * before any data is actually written. | |
1032 | */ | |
1033 | ||
1034 | METHODDEF(void) | |
1035 | init_destination (j_compress_ptr cinfo) | |
1036 | { | |
1037 | my_dest_ptr dest = (my_dest_ptr) cinfo->dest; | |
1038 | ||
1039 | /* Allocate the output buffer --- it will be released when done with image */ | |
1040 | dest->buffer = (JOCTET *) | |
1041 | (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, | |
1042 | OUTPUT_BUF_SIZE * SIZEOF(JOCTET)); | |
1043 | ||
1044 | dest->pub.next_output_byte = dest->buffer; | |
1045 | dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; | |
1046 | } | |
1047 | ||
1048 | ||
1049 | /* | |
1050 | * Empty the output buffer --- called whenever buffer fills up. | |
1051 | * | |
1052 | * In typical applications, this should write the entire output buffer | |
1053 | * (ignoring the current state of next_output_byte & free_in_buffer), | |
1054 | * reset the pointer & count to the start of the buffer, and return TRUE | |
1055 | * indicating that the buffer has been dumped. | |
1056 | * | |
1057 | * In applications that need to be able to suspend compression due to output | |
1058 | * overrun, a FALSE return indicates that the buffer cannot be emptied now. | |
1059 | * In this situation, the compressor will return to its caller (possibly with | |
1060 | * an indication that it has not accepted all the supplied scanlines). The | |
1061 | * application should resume compression after it has made more room in the | |
1062 | * output buffer. Note that there are substantial restrictions on the use of | |
1063 | * suspension --- see the documentation. | |
1064 | * | |
1065 | * When suspending, the compressor will back up to a convenient restart point | |
1066 | * (typically the start of the current MCU). next_output_byte & free_in_buffer | |
1067 | * indicate where the restart point will be if the current call returns FALSE. | |
1068 | * Data beyond this point will be regenerated after resumption, so do not | |
1069 | * write it out when emptying the buffer externally. | |
1070 | */ | |
1071 | ||
1072 | METHODDEF(boolean) | |
1073 | empty_output_buffer (j_compress_ptr cinfo) | |
1074 | { | |
1075 | my_dest_ptr dest = (my_dest_ptr) cinfo->dest; | |
1076 | ||
1077 | //if (JFWRITE(dest->outfile, dest->buffer, OUTPUT_BUF_SIZE) != | |
1078 | // (size_t) OUTPUT_BUF_SIZE) | |
1079 | // ERREXIT(cinfo, JERR_FILE_WRITE); | |
1080 | size_t output_buf_size = OUTPUT_BUF_SIZE; | |
1081 | if( !dest->outfile->write((char*)dest->buffer, output_buf_size) ) | |
1082 | { | |
1083 | ERREXIT(cinfo, JERR_FILE_WRITE); | |
1084 | } | |
1085 | ||
1086 | dest->pub.next_output_byte = dest->buffer; | |
1087 | dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; | |
1088 | ||
1089 | return TRUE; | |
1090 | } | |
1091 | ||
1092 | ||
1093 | /* | |
1094 | * Terminate destination --- called by jpeg_finish_compress | |
1095 | * after all data has been written. Usually needs to flush buffer. | |
1096 | * | |
1097 | * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding | |
1098 | * application must deal with any cleanup that should happen even | |
1099 | * for error exit. | |
1100 | */ | |
1101 | ||
1102 | METHODDEF(void) | |
1103 | term_destination (j_compress_ptr cinfo) | |
1104 | { | |
1105 | my_dest_ptr dest = (my_dest_ptr) cinfo->dest; | |
1106 | size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer; | |
1107 | ||
1108 | /* Write any data remaining in the buffer */ | |
1109 | if (datacount > 0) { | |
1110 | //if (JFWRITE(dest->outfile, dest->buffer, datacount) != datacount) | |
1111 | // ERREXIT(cinfo, JERR_FILE_WRITE); | |
1112 | if( !dest->outfile->write((char*)dest->buffer, datacount) ) | |
1113 | ERREXIT(cinfo, JERR_FILE_WRITE); | |
1114 | } | |
1115 | //fflush(dest->outfile); | |
1116 | dest->outfile->flush(); | |
1117 | /* Make sure we wrote the output file OK */ | |
1118 | //if (ferror(dest->outfile)) | |
1119 | if (dest->outfile->fail()) | |
1120 | ERREXIT(cinfo, JERR_FILE_WRITE); | |
1121 | } | |
1122 | ||
1123 | ||
1124 | /* | |
1125 | * Prepare for output to a stdio stream. | |
1126 | * The caller must have already opened the stream, and is responsible | |
1127 | * for closing it after finishing compression. | |
1128 | */ | |
1129 | ||
1130 | GLOBAL(void) | |
1131 | jpeg_stdio_dest (j_compress_ptr cinfo, /*FILE * */ std::ostream * outfile) | |
1132 | { | |
1133 | my_dest_ptr dest; | |
1134 | ||
1135 | /* The destination object is made permanent so that multiple JPEG images | |
1136 | * can be written to the same file without re-executing jpeg_stdio_dest. | |
1137 | * This makes it dangerous to use this manager and a different destination | |
1138 | * manager serially with the same JPEG object, because their private object | |
1139 | * sizes may be different. Caveat programmer. | |
1140 | */ | |
1141 | if (cinfo->dest == NULL) { /* first time for this JPEG object? */ | |
1142 | cinfo->dest = (struct jpeg_destination_mgr *) | |
1143 | (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, | |
1144 | SIZEOF(my_destination_mgr)); | |
1145 | } | |
1146 | ||
1147 | dest = (my_dest_ptr) cinfo->dest; | |
1148 | dest->pub.init_destination = init_destination; | |
1149 | dest->pub.empty_output_buffer = empty_output_buffer; | |
1150 | dest->pub.term_destination = term_destination; | |
1151 | dest->outfile = outfile; | |
1152 | } | |
1153 | ||
1154 | /* | |
1155 | * Sample routine for JPEG compression. We assume that the target file name | |
1156 | * and a compression quality factor are passed in. | |
1157 | */ | |
1158 | ||
1159 | bool JPEGBITSCodec::InternalCode(const char* input, unsigned long len, std::ostream &os) | |
1160 | { | |
1161 | int quality = 100; (void)len; | |
1162 | (void)quality; | |
1163 | JSAMPLE * image_buffer = (JSAMPLE*)input; /* Points to large array of R,G,B-order data */ | |
1164 | const unsigned int *dims = this->GetDimensions(); | |
1165 | int image_height = dims[1]; /* Number of rows in image */ | |
1166 | int image_width = dims[0]; /* Number of columns in image */ | |
1167 | ||
1168 | /* This struct contains the JPEG compression parameters and pointers to | |
1169 | * working space (which is allocated as needed by the JPEG library). | |
1170 | * It is possible to have several such structures, representing multiple | |
1171 | * compression/decompression processes, in existence at once. We refer | |
1172 | * to any one struct (and its associated working data) as a "JPEG object". | |
1173 | */ | |
1174 | struct jpeg_compress_struct cinfo; | |
1175 | /* This struct represents a JPEG error handler. It is declared separately | |
1176 | * because applications often want to supply a specialized error handler | |
1177 | * (see the second half of this file for an example). But here we just | |
1178 | * take the easy way out and use the standard error handler, which will | |
1179 | * print a message on stderr and call exit() if compression fails. | |
1180 | * Note that this struct must live as long as the main JPEG parameter | |
1181 | * struct, to avoid dangling-pointer problems. | |
1182 | */ | |
1183 | struct jpeg_error_mgr jerr; | |
1184 | /* More stuff */ | |
1185 | //FILE * outfile; /* target file */ | |
1186 | std::ostream * outfile = &os; | |
1187 | JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ | |
1188 | size_t row_stride; /* physical row width in image buffer */ | |
1189 | ||
1190 | /* Step 1: allocate and initialize JPEG compression object */ | |
1191 | ||
1192 | /* We have to set up the error handler first, in case the initialization | |
1193 | * step fails. (Unlikely, but it could happen if you are out of memory.) | |
1194 | * This routine fills in the contents of struct jerr, and returns jerr's | |
1195 | * address which we place into the link field in cinfo. | |
1196 | */ | |
1197 | cinfo.err = jpeg_std_error(&jerr); | |
1198 | /* Now we can initialize the JPEG compression object. */ | |
1199 | jpeg_create_compress(&cinfo); | |
1200 | ||
1201 | /* Step 2: specify data destination (eg, a file) */ | |
1202 | /* Note: steps 2 and 3 can be done in either order. */ | |
1203 | ||
1204 | /* Here we use the library-supplied code to send compressed data to a | |
1205 | * stdio stream. You can also write your own code to do something else. | |
1206 | * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that | |
1207 | * requires it in order to write binary files. | |
1208 | */ | |
1209 | //if ((outfile = fopen(filename, "wb")) == NULL) { | |
1210 | // fprintf(stderr, "can't open %s\n", filename); | |
1211 | // exit(1); | |
1212 | //} | |
1213 | jpeg_stdio_dest(&cinfo, outfile); | |
1214 | ||
1215 | /* Step 3: set parameters for compression */ | |
1216 | ||
1217 | /* First we supply a description of the input image. | |
1218 | * Four fields of the cinfo struct must be filled in: | |
1219 | */ | |
1220 | cinfo.image_width = image_width; /* image width and height, in pixels */ | |
1221 | cinfo.image_height = image_height; | |
1222 | ||
1223 | switch( this->GetPhotometricInterpretation() ) | |
1224 | { | |
1225 | case PhotometricInterpretation::MONOCHROME1: | |
1226 | case PhotometricInterpretation::MONOCHROME2: | |
1227 | case PhotometricInterpretation::PALETTE_COLOR: | |
1228 | cinfo.input_components = 1; /* # of color components per pixel */ | |
1229 | cinfo.in_color_space = JCS_GRAYSCALE; /* colorspace of input image */ | |
1230 | break; | |
1231 | case PhotometricInterpretation::RGB: | |
1232 | case PhotometricInterpretation::YBR_RCT: | |
1233 | case PhotometricInterpretation::YBR_ICT: | |
1234 | cinfo.input_components = 3; /* # of color components per pixel */ | |
1235 | cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ | |
1236 | break; | |
1237 | case PhotometricInterpretation::YBR_FULL: | |
1238 | case PhotometricInterpretation::YBR_FULL_422: | |
1239 | case PhotometricInterpretation::YBR_PARTIAL_420: | |
1240 | case PhotometricInterpretation::YBR_PARTIAL_422: | |
1241 | cinfo.input_components = 3; /* # of color components per pixel */ | |
1242 | cinfo.in_color_space = JCS_YCbCr; /* colorspace of input image */ | |
1243 | break; | |
1244 | case PhotometricInterpretation::HSV: | |
1245 | case PhotometricInterpretation::ARGB: | |
1246 | case PhotometricInterpretation::CMYK: | |
1247 | // TODO ! | |
1248 | case PhotometricInterpretation::UNKNOWN: | |
1249 | case PhotometricInterpretation::PI_END: // To please compiler | |
1250 | return false; | |
1251 | } | |
1252 | //if ( cinfo.process == JPROC_LOSSLESS ) | |
1253 | // { | |
1254 | // cinfo.in_color_space = JCS_UNKNOWN; | |
1255 | // } | |
1256 | //assert( cinfo.image_height * cinfo.image_width * cinfo.input_components * sizeof(JSAMPLE) == len ); | |
1257 | ||
1258 | /* Now use the library's routine to set default compression parameters. | |
1259 | * (You must set at least cinfo.in_color_space before calling this, | |
1260 | * since the defaults depend on the source color space.) | |
1261 | */ | |
1262 | jpeg_set_defaults(&cinfo); | |
1263 | ||
1264 | /* | |
1265 | * predictor = 1 | |
1266 | * point_transform = 0 | |
1267 | * => lossless transformation. | |
1268 | * Basicaly you need to have point_transform = 0, but you can pick whichever predictor [1...7] you want | |
1269 | * TODO: is there a way to pick the right predictor (best compression/fastest ?) | |
1270 | */ | |
1271 | if( !LossyFlag ) | |
1272 | { | |
1273 | jpeg_simple_lossless (&cinfo, 1, 0); | |
1274 | //jpeg_simple_lossless (&cinfo, 7, 0); | |
1275 | } | |
1276 | ||
1277 | /* Now you can set any non-default parameters you wish to. | |
1278 | * Here we just illustrate the use of quality (quantization table) scaling: | |
1279 | */ | |
1280 | if( !LossyFlag ) | |
1281 | { | |
1282 | assert( Quality == 100 ); | |
1283 | } | |
1284 | jpeg_set_quality(&cinfo, Quality, TRUE /* limit to baseline-JPEG values */); | |
1285 | ||
1286 | /* | |
1287 | * See write_file_header | |
1288 | */ | |
1289 | cinfo.write_JFIF_header = 0; | |
1290 | //cinfo.density_unit = 2; | |
1291 | //cinfo.X_density = 2; | |
1292 | //cinfo.Y_density = 5; | |
1293 | ||
1294 | /* Step 4: Start compressor */ | |
1295 | ||
1296 | /* TRUE ensures that we will write a complete interchange-JPEG file. | |
1297 | * Pass TRUE unless you are very sure of what you're doing. | |
1298 | */ | |
1299 | jpeg_start_compress(&cinfo, TRUE); | |
1300 | ||
1301 | /* Step 5: while (scan lines remain to be written) */ | |
1302 | /* jpeg_write_scanlines(...); */ | |
1303 | ||
1304 | /* Here we use the library's state variable cinfo.next_scanline as the | |
1305 | * loop counter, so that we don't have to keep track ourselves. | |
1306 | * To keep things simple, we pass one scanline per call; you can pass | |
1307 | * more if you wish, though. | |
1308 | */ | |
1309 | row_stride = image_width * cinfo.input_components; /* JSAMPLEs per row in image_buffer */ | |
1310 | ||
1311 | if( this->GetPlanarConfiguration() == 0 ) | |
1312 | { | |
1313 | while (cinfo.next_scanline < cinfo.image_height) { | |
1314 | /* jpeg_write_scanlines expects an array of pointers to scanlines. | |
1315 | * Here the array is only one element long, but you could pass | |
1316 | * more than one scanline at a time if that's more convenient. | |
1317 | */ | |
1318 | row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride]; | |
1319 | (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); | |
1320 | } | |
1321 | } | |
1322 | else | |
1323 | { | |
1324 | /* | |
1325 | * warning: Need to read C.7.6.3.1.3 Planar Configuration (see note about Planar Configuration dummy value) | |
1326 | */ | |
1327 | JSAMPLE *tempbuffer = (JSAMPLE*)malloc( row_stride * sizeof(JSAMPLE) ); | |
1328 | row_pointer[0] = tempbuffer; | |
1329 | int offset = image_height * image_width; | |
1330 | while (cinfo.next_scanline < cinfo.image_height) { | |
1331 | assert( row_stride % 3 == 0 ); | |
1332 | JSAMPLE* ptempbuffer = tempbuffer; | |
1333 | JSAMPLE* red = image_buffer + cinfo.next_scanline * row_stride / 3; | |
1334 | JSAMPLE* green = image_buffer + cinfo.next_scanline * row_stride / 3 + offset; | |
1335 | JSAMPLE* blue = image_buffer + cinfo.next_scanline * row_stride / 3 + offset * 2; | |
1336 | for(size_t i = 0; i < row_stride / 3; ++i ) | |
1337 | { | |
1338 | *ptempbuffer++ = *red++; | |
1339 | *ptempbuffer++ = *green++; | |
1340 | *ptempbuffer++ = *blue++; | |
1341 | } | |
1342 | (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); | |
1343 | } | |
1344 | free(tempbuffer); | |
1345 | } | |
1346 | ||
1347 | /* Step 6: Finish compression */ | |
1348 | ||
1349 | jpeg_finish_compress(&cinfo); | |
1350 | /* After finish_compress, we can close the output file. */ | |
1351 | //fclose(outfile); | |
1352 | ||
1353 | /* Step 7: release JPEG compression object */ | |
1354 | ||
1355 | /* This is an important step since it will release a good deal of memory. */ | |
1356 | jpeg_destroy_compress(&cinfo); | |
1357 | ||
1358 | /* And we're done! */ | |
1359 | return true; | |
1360 | } | |
1361 | ||
1362 | bool JPEGBITSCodec::EncodeBuffer(std::ostream &os, const char *data, size_t datalen) | |
1363 | { | |
1364 | (void)datalen; | |
1365 | JSAMPLE * image_buffer = (JSAMPLE*)data; /* Points to large array of R,G,B-order data */ | |
1366 | const unsigned int *dims = this->GetDimensions(); | |
1367 | int image_height = dims[1]; /* Number of rows in image */ | |
1368 | int image_width = dims[0]; /* Number of columns in image */ | |
1369 | ||
1370 | /* This struct contains the JPEG compression parameters and pointers to | |
1371 | * working space (which is allocated as needed by the JPEG library). | |
1372 | * It is possible to have several such structures, representing multiple | |
1373 | * compression/decompression processes, in existence at once. We refer | |
1374 | * to any one struct (and its associated working data) as a "JPEG object". | |
1375 | */ | |
1376 | jpeg_compress_struct &cinfo = Internals->cinfo_comp; | |
1377 | /* This struct represents a JPEG error handler. It is declared separately | |
1378 | * because applications often want to supply a specialized error handler | |
1379 | * (see the second half of this file for an example). But here we just | |
1380 | * take the easy way out and use the standard error handler, which will | |
1381 | * print a message on stderr and call exit() if compression fails. | |
1382 | * Note that this struct must live as long as the main JPEG parameter | |
1383 | * struct, to avoid dangling-pointer problems. | |
1384 | */ | |
1385 | my_error_mgr &jerr = Internals->jerr; | |
1386 | /* More stuff */ | |
1387 | //FILE * outfile; /* target file */ | |
1388 | std::ostream *outfile = &os; | |
1389 | JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ | |
1390 | size_t row_stride; /* physical row width in image buffer */ | |
1391 | ||
1392 | if( Internals->StateSuspension == 0 ) | |
1393 | { | |
1394 | /* Step 1: allocate and initialize JPEG compression object */ | |
1395 | ||
1396 | /* We have to set up the error handler first, in case the initialization | |
1397 | * step fails. (Unlikely, but it could happen if you are out of memory.) | |
1398 | * This routine fills in the contents of struct jerr, and returns jerr's | |
1399 | * address which we place into the link field in cinfo. | |
1400 | */ | |
1401 | cinfo.err = jpeg_std_error(&jerr.pub); | |
1402 | /* Now we can initialize the JPEG compression object. */ | |
1403 | jpeg_create_compress(&cinfo); | |
1404 | ||
1405 | /* Step 2: specify data destination (eg, a file) */ | |
1406 | /* Note: steps 2 and 3 can be done in either order. */ | |
1407 | ||
1408 | /* Here we use the library-supplied code to send compressed data to a | |
1409 | * stdio stream. You can also write your own code to do something else. | |
1410 | * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that | |
1411 | * requires it in order to write binary files. | |
1412 | */ | |
1413 | //if ((outfile = fopen(filename, "wb")) == NULL) { | |
1414 | // fprintf(stderr, "can't open %s\n", filename); | |
1415 | // exit(1); | |
1416 | //} | |
1417 | } | |
1418 | if( Internals->StateSuspension == 0 ) | |
1419 | { | |
1420 | jpeg_stdio_dest(&cinfo, outfile); | |
1421 | } | |
1422 | ||
1423 | /* Step 3: set parameters for compression */ | |
1424 | ||
1425 | /* First we supply a description of the input image. | |
1426 | * Four fields of the cinfo struct must be filled in: | |
1427 | */ | |
1428 | if( Internals->StateSuspension == 0 ) | |
1429 | { | |
1430 | cinfo.image_width = image_width; /* image width and height, in pixels */ | |
1431 | cinfo.image_height = image_height; | |
1432 | } | |
1433 | ||
1434 | if( Internals->StateSuspension == 0 ) | |
1435 | { | |
1436 | switch( this->GetPhotometricInterpretation() ) | |
1437 | { | |
1438 | case PhotometricInterpretation::MONOCHROME1: | |
1439 | case PhotometricInterpretation::MONOCHROME2: | |
1440 | case PhotometricInterpretation::PALETTE_COLOR: | |
1441 | cinfo.input_components = 1; /* # of color components per pixel */ | |
1442 | cinfo.in_color_space = JCS_GRAYSCALE; /* colorspace of input image */ | |
1443 | break; | |
1444 | case PhotometricInterpretation::RGB: | |
1445 | case PhotometricInterpretation::YBR_RCT: | |
1446 | case PhotometricInterpretation::YBR_ICT: | |
1447 | cinfo.input_components = 3; /* # of color components per pixel */ | |
1448 | cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ | |
1449 | break; | |
1450 | case PhotometricInterpretation::YBR_FULL: | |
1451 | case PhotometricInterpretation::YBR_FULL_422: | |
1452 | case PhotometricInterpretation::YBR_PARTIAL_420: | |
1453 | case PhotometricInterpretation::YBR_PARTIAL_422: | |
1454 | cinfo.input_components = 3; /* # of color components per pixel */ | |
1455 | cinfo.in_color_space = JCS_YCbCr; /* colorspace of input image */ | |
1456 | break; | |
1457 | case PhotometricInterpretation::HSV: | |
1458 | case PhotometricInterpretation::ARGB: | |
1459 | case PhotometricInterpretation::CMYK: | |
1460 | // TODO ! | |
1461 | case PhotometricInterpretation::UNKNOWN: | |
1462 | case PhotometricInterpretation::PI_END: // To please compiler | |
1463 | return false; | |
1464 | } | |
1465 | } | |
1466 | //if ( cinfo.process == JPROC_LOSSLESS ) | |
1467 | // { | |
1468 | // cinfo.in_color_space = JCS_UNKNOWN; | |
1469 | // } | |
1470 | //assert( cinfo.image_height * cinfo.image_width * cinfo.input_components * sizeof(JSAMPLE) == len ); | |
1471 | ||
1472 | /* Now use the library's routine to set default compression parameters. | |
1473 | * (You must set at least cinfo.in_color_space before calling this, | |
1474 | * since the defaults depend on the source color space.) | |
1475 | */ | |
1476 | if( Internals->StateSuspension == 0 ) | |
1477 | { | |
1478 | jpeg_set_defaults(&cinfo); | |
1479 | } | |
1480 | ||
1481 | /* | |
1482 | * predictor = 1 | |
1483 | * point_transform = 0 | |
1484 | * => lossless transformation. | |
1485 | * Basicaly you need to have point_transform = 0, but you can pick whichever predictor [1...7] you want | |
1486 | * TODO: is there a way to pick the right predictor (best compression/fastest ?) | |
1487 | */ | |
1488 | if( Internals->StateSuspension == 0 ) | |
1489 | { | |
1490 | if( !LossyFlag ) | |
1491 | { | |
1492 | jpeg_simple_lossless (&cinfo, 1, 0); | |
1493 | //jpeg_simple_lossless (&cinfo, 7, 0); | |
1494 | } | |
1495 | } | |
1496 | ||
1497 | /* Now you can set any non-default parameters you wish to. | |
1498 | * Here we just illustrate the use of quality (quantization table) scaling: | |
1499 | */ | |
1500 | if( !LossyFlag ) | |
1501 | { | |
1502 | assert( Quality == 100 ); | |
1503 | } | |
1504 | if( Internals->StateSuspension == 0 ) | |
1505 | { | |
1506 | jpeg_set_quality(&cinfo, Quality, TRUE /* limit to baseline-JPEG values */); | |
1507 | } | |
1508 | ||
1509 | if( Internals->StateSuspension == 0 ) | |
1510 | { | |
1511 | /* | |
1512 | * See write_file_header | |
1513 | */ | |
1514 | cinfo.write_JFIF_header = 0; | |
1515 | } | |
1516 | //cinfo.density_unit = 2; | |
1517 | //cinfo.X_density = 2; | |
1518 | //cinfo.Y_density = 5; | |
1519 | ||
1520 | /* Step 4: Start compressor */ | |
1521 | ||
1522 | if( Internals->StateSuspension == 0 ) | |
1523 | { | |
1524 | /* TRUE ensures that we will write a complete interchange-JPEG file. | |
1525 | * Pass TRUE unless you are very sure of what you're doing. | |
1526 | */ | |
1527 | jpeg_start_compress(&cinfo, TRUE); | |
1528 | Internals->StateSuspension = 1; | |
1529 | } | |
1530 | ||
1531 | /* Step 5: while (scan lines remain to be written) */ | |
1532 | /* jpeg_write_scanlines(...); */ | |
1533 | ||
1534 | /* Here we use the library's state variable cinfo.next_scanline as the | |
1535 | * loop counter, so that we don't have to keep track ourselves. | |
1536 | * To keep things simple, we pass one scanline per call; you can pass | |
1537 | * more if you wish, though. | |
1538 | */ | |
1539 | row_stride = image_width * cinfo.input_components; /* JSAMPLEs per row in image_buffer */ | |
1540 | ||
1541 | if ( Internals->StateSuspension == 1 ) | |
1542 | { | |
1543 | assert( this->GetPlanarConfiguration() == 0 ); | |
1544 | assert( row_stride * sizeof(JSAMPLE) == datalen ); | |
1545 | { | |
1546 | //while (cinfo.next_scanline < cinfo.image_height) { | |
1547 | /* jpeg_write_scanlines expects an array of pointers to scanlines. | |
1548 | * Here the array is only one element long, but you could pass | |
1549 | * more than one scanline at a time if that's more convenient. | |
1550 | */ | |
1551 | row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride * 0]; | |
1552 | const JDIMENSION nscanline = jpeg_write_scanlines(&cinfo, row_pointer, 1); | |
1553 | assert( nscanline == 1 ); (void)nscanline; | |
1554 | assert(cinfo.next_scanline <= cinfo.image_height); | |
1555 | //} | |
1556 | } | |
1557 | if(cinfo.next_scanline == cinfo.image_height) | |
1558 | { | |
1559 | Internals->StateSuspension = 2; | |
1560 | } | |
1561 | } | |
1562 | ||
1563 | /* Step 6: Finish compression */ | |
1564 | ||
1565 | if (Internals->StateSuspension == 2 ) | |
1566 | { | |
1567 | jpeg_finish_compress(&cinfo); | |
1568 | /* After finish_compress, we can close the output file. */ | |
1569 | //fclose(outfile); | |
1570 | } | |
1571 | ||
1572 | /* Step 7: release JPEG compression object */ | |
1573 | ||
1574 | if (Internals->StateSuspension == 2 ) | |
1575 | { | |
1576 | /* This is an important step since it will release a good deal of memory. */ | |
1577 | jpeg_destroy_compress(&cinfo); | |
1578 | ||
1579 | Internals->StateSuspension = 0; | |
1580 | } | |
1581 | ||
1582 | /* And we're done! */ | |
1583 | return true; | |
1584 | } | |
1585 | ||
1586 | bool JPEGBITSCodec::IsStateSuspension() const | |
1587 | { | |
1588 | return Internals->StateSuspension != 0; | |
1589 | } | |
1590 | ||
1591 | } // end namespace gdcm |
185 | 185 | if( NumberOfDimensions == 2 ) |
186 | 186 | { |
187 | 187 | const SequenceOfFragments *sf = in.GetSequenceOfFragments(); |
188 | assert( sf ); | |
188 | if (!sf) return false; | |
189 | 189 | unsigned long totalLen = sf->ComputeByteLength(); |
190 | 190 | char *buffer = new char[totalLen]; |
191 | 191 | sf->GetBuffer(buffer, totalLen); |
203 | 203 | else if( NumberOfDimensions == 3 ) |
204 | 204 | { |
205 | 205 | const SequenceOfFragments *sf = in.GetSequenceOfFragments(); |
206 | assert( sf ); | |
207 | gdcmAssertAlwaysMacro( sf->GetNumberOfFragments() == Dimensions[2] ); | |
206 | if (!sf) return false; | |
207 | if (sf->GetNumberOfFragments() != Dimensions[2]) return false; | |
208 | 208 | std::stringstream os; |
209 | 209 | for(unsigned int i = 0; i < sf->GetNumberOfFragments(); ++i) |
210 | 210 | { |
211 | 211 | const Fragment &frag = sf->GetFragment(i); |
212 | 212 | if( frag.IsEmpty() ) return false; |
213 | 213 | const ByteValue *bv = frag.GetByteValue(); |
214 | assert( bv ); | |
214 | if (!bv) return false; | |
215 | 215 | size_t totalLen = bv->GetLength(); |
216 | 216 | char *mybuffer = new char[totalLen]; |
217 | 217 |
39 | 39 | } |
40 | 40 | |
41 | 41 | |
42 | static uint8_t reverseBitsByte(uint8_t x) | |
43 | { | |
44 | uint8_t b = 0; | |
45 | for (int i = 0; i < 8; ++i) { | |
46 | b <<= 1; | |
47 | b |= (x & 1); | |
48 | x >>= 1; | |
49 | } | |
50 | return b; | |
51 | } | |
42 | 52 | |
43 | 53 | bool PNMCodec::Write(const char *filename, const DataElement &out) const |
44 | 54 | { |
45 | 55 | std::ofstream os(filename, std::ios::binary); |
46 | 56 | const unsigned int *dims = this->GetDimensions(); |
47 | 57 | const PhotometricInterpretation &pi = this->GetPhotometricInterpretation(); |
58 | const PixelFormat& pf = GetPixelFormat(); | |
48 | 59 | if( pi == PhotometricInterpretation::MONOCHROME2 |
49 | 60 | || pi == PhotometricInterpretation::MONOCHROME1 ) // warning viz will be surprising |
50 | 61 | { |
51 | os << "P5\n"; | |
62 | // FIXME possible mismatch pi vs pf (eg. pbm with mono2) | |
63 | if( pf == PixelFormat::SINGLEBIT) | |
64 | os << "P4\n"; | |
65 | else | |
66 | os << "P5\n"; | |
52 | 67 | } |
53 | 68 | else if( pi == PhotometricInterpretation::RGB |
54 | 69 | || pi == PhotometricInterpretation::PALETTE_COLOR ) |
69 | 84 | return false; |
70 | 85 | } |
71 | 86 | |
72 | const PixelFormat& pf = GetPixelFormat(); | |
73 | 87 | switch(pf) |
74 | 88 | { |
89 | case PixelFormat::SINGLEBIT: | |
90 | break; | |
75 | 91 | case PixelFormat::UINT8: |
76 | 92 | //case PixelFormat::INT8: |
77 | os << "255"; | |
93 | os << "255\n"; | |
78 | 94 | break; |
79 | 95 | case PixelFormat::UINT16: |
80 | 96 | //case PixelFormat::INT16: |
81 | os << "65535"; | |
97 | os << "65535\n"; | |
82 | 98 | break; |
83 | 99 | default: |
84 | 100 | gdcmErrorMacro( "Unhandled PF: " << pf ); |
85 | 101 | return false; |
86 | 102 | } |
87 | os << "\n"; | |
88 | 103 | |
89 | 104 | const ByteValue *bv = out.GetByteValue(); |
90 | 105 | // FIXME: PNM Codec cannot handle encapsulated syntax... sigh |
108 | 123 | if( pf.GetBitsAllocated() == 16 ) |
109 | 124 | { |
110 | 125 | bv->Write<SwapperDoOp, uint16_t>( os ); |
126 | } | |
127 | else if( pf.GetBitsAllocated() == 1 ) | |
128 | { | |
129 | const uint8_t *x = (const uint8_t*) bv->GetPointer(); | |
130 | for( size_t i = 0; i < bv->GetLength(); i++ ) | |
131 | { | |
132 | uint8_t b = reverseBitsByte(x[i]); | |
133 | os.write((char*)&b, 1); | |
134 | } | |
111 | 135 | } |
112 | 136 | else |
113 | 137 | { |
235 | 259 | std::string type, str; |
236 | 260 | std::getline(is,type); |
237 | 261 | PhotometricInterpretation pi; |
238 | if( type == "P5" ) | |
262 | if( type == "P4" ) // P4 => mono W/B ! | |
263 | pi = PhotometricInterpretation::MONOCHROME1; | |
264 | else if( type == "P5" ) | |
239 | 265 | pi = PhotometricInterpretation::MONOCHROME2; |
240 | 266 | else if( type == "P6" ) // P3 => ASCII |
241 | 267 | pi = PhotometricInterpretation::RGB; |
254 | 280 | unsigned int dims[3] = {}; |
255 | 281 | is >> dims[0]; is >> dims[1]; |
256 | 282 | unsigned int maxval; |
257 | is >> maxval; | |
283 | if( type == "P4" ) | |
284 | maxval = 1; | |
285 | else | |
286 | is >> maxval; | |
258 | 287 | // http://netpbm.sourceforge.net/doc/pgm.html |
259 | 288 | // some kind of empty line... |
260 | 289 | if( is.peek() == '\n' ) |
265 | 294 | //assert(len < INT_MAX); |
266 | 295 | //assert(pos < INT_MAX); |
267 | 296 | size_t m = ((size_t)len - (size_t)pos ) / ( dims[0]*dims[1] ); |
268 | if( m * dims[0] * dims[1] != (size_t)len - pos ) | |
297 | bool cond; | |
298 | if( type == "P4" ) { | |
299 | const size_t bytesPerRow = dims[0] / 8 + (dims[0] % 8 != 0 ? 1 : 0); | |
300 | cond = bytesPerRow * dims[1] != ((size_t)len - (size_t)pos); | |
301 | } | |
302 | else | |
303 | cond = m * dims[0] * dims[1] != (size_t)len - (size_t)pos; | |
304 | if( cond ) | |
269 | 305 | { |
270 | 306 | std::cerr << "Problem computing length" << std::endl; |
271 | 307 | std::cerr << "Pos: " << len - pos << std::endl; |
301 | 337 | #else |
302 | 338 | const int nbits = log2( maxval ); |
303 | 339 | // handle case where nbits = 0 also: |
304 | if( nbits > 0 && nbits <= 8 ) | |
340 | if( nbits > 0 && nbits <= 1 ) | |
341 | { | |
342 | pf.SetBitsAllocated( 1 ); | |
343 | } | |
344 | else if( nbits > 1 && nbits <= 8 ) | |
305 | 345 | { |
306 | 346 | pf.SetBitsAllocated( 8 ); |
307 | 347 | pf.SetBitsStored( (unsigned short)nbits ); |
331 | 371 | //image.SetTransferSyntax( TransferSyntax::ExplicitVRBigEndian ); // PGM are big endian |
332 | 372 | //image.SetTransferSyntax( TransferSyntax::ExplicitVRLittleEndian ); // PGM are big endian |
333 | 373 | //image.SetTransferSyntax( TransferSyntax::ImplicitVRBigEndianPrivateGE ); // PGM are big endian |
334 | if( pf.GetBitsAllocated() == 8 ) | |
374 | if( pf.GetBitsAllocated() > 8 ) | |
375 | ts = TransferSyntax::ImplicitVRBigEndianPrivateGE; | |
376 | else | |
335 | 377 | //ts = TransferSyntax::ImplicitVRLittleEndian; // nicer to handle than private GE |
336 | 378 | ts = TransferSyntax::ExplicitVRLittleEndian; // nicer to handle than private GE |
337 | else | |
338 | ts = TransferSyntax::ImplicitVRBigEndianPrivateGE; | |
339 | 379 | |
340 | 380 | SetPhotometricInterpretation( pi ); |
341 | 381 | SetPixelFormat( pf ); |
296 | 296 | b += 3; |
297 | 297 | } |
298 | 298 | assert( b == input + length + 2); |
299 | assert ( pout = output + length ); | |
299 | assert ( pout == output + length ); | |
300 | 300 | return true; |
301 | 301 | } |
302 | 302 | |
846 | 846 | } |
847 | 847 | //assert( numberOfReadBytes + frame.Header.Offset[i] - is.tellg() + start == 0); |
848 | 848 | } |
849 | assert( numOutBytes == length ); | |
849 | if( numOutBytes != length ) return false; | |
850 | 850 | } |
851 | 851 | |
852 | 852 | return ImageCodec::DecodeByStreams(tmpos,os); |
65 | 65 | { "c6188f2ae06a55d596d4d6b4d914b404f7bf5786" , "D_CLUNIE_RG2_JPLY.dcm" }, |
66 | 66 | { "5035a6298cf8590932605cb4bb10f128df971fcb" , "D_CLUNIE_RG2_RLE.dcm" }, |
67 | 67 | { "d2a56de2e035095c3dea9be80878f9607c63728d" , "D_CLUNIE_RG3_JPLL.dcm" }, |
68 | { "41abc80638b12a2601e7764805a9c4ddc385bdc5" , "D_CLUNIE_RG3_JPLY.dcm" }, | |
68 | { "c90b8543259ca7189fa76201f864c2f32e6ebef3" , "D_CLUNIE_RG3_JPLY.dcm" }, | |
69 | 69 | { "eb417a88c6b3fe6c5768ab705990fc0d54558816" , "D_CLUNIE_RG3_RLE.dcm" }, |
70 | 70 | { "8e27c853a156038e1f6daebb04f2c9059ebfbd82" , "D_CLUNIE_SC1_JPLY.dcm" }, |
71 | 71 | { "6a6ca811ae87ae1ca4549f49724b58562eea714b" , "D_CLUNIE_SC1_RLE.dcm" }, |
234 | 234 | { "08828e913a7a1ebbc0129c42974b64ce702814b6" , "JPEGNote_missing.dcm" }, |
235 | 235 | { "99c169688190a66100b61319eaeefb3db1936125" , "RLEDebianBug816607Orig.dcm" }, |
236 | 236 | { "f18f91631b59f0242b5daca547878e4c5cbf6a5b" , "GE_MR_0025xx1bProtocolDataBlockXML.dcm" }, |
237 | { "8c46efd571b33264d7c0bed14fb6dd0282330b92" , "JPEGLS_CharLS_10742.dcm" }, | |
237 | 238 | |
238 | 239 | { NULL, NULL} |
239 | 240 | }; |
43 | 43 | std::cerr << "Error" << std::endl; |
44 | 44 | return 1; |
45 | 45 | } |
46 | return 0; | |
47 | } | |
48 | ||
49 | int TestMakeDirectory() | |
50 | { | |
51 | std::string tmpdir = gdcm::Testing::GetTempDirectory(); | |
52 | if( !gdcm::System::FileIsDirectory( tmpdir.c_str() )) return 1; | |
53 | const char subpath[] = "TestSystem1"; | |
54 | std::string subdir = gdcm::Testing::GetTempDirectory(subpath); | |
55 | if( !gdcm::System::MakeDirectory( subdir.c_str() )) return 1; | |
56 | if( !gdcm::System::FileIsDirectory( subdir.c_str() )) return 1; | |
57 | const char multipath[] = "TestSystem42/another/dir"; | |
58 | std::string subdir2 = gdcm::Testing::GetTempDirectory(multipath); | |
59 | if( !gdcm::System::MakeDirectory( subdir2.c_str() )) return 1; | |
60 | if( !gdcm::System::FileIsDirectory( subdir2.c_str() )) return 1; | |
46 | 61 | return 0; |
47 | 62 | } |
48 | 63 | |
364 | 379 | } |
365 | 380 | int res = 0; |
366 | 381 | res += TestGetTimeOfDay(); |
382 | res += TestMakeDirectory(); | |
367 | 383 | |
368 | 384 | const char * testfilesize = gdcm::Testing::GetTempFilename( "filesize.bin" ); |
369 | 385 | if( gdcm::System::FileExists( testfilesize ) ) |
12 | 12 | =========================================================================*/ |
13 | 13 | #include "gdcmFileMetaInformation.h" |
14 | 14 | |
15 | #include "gdcmReader.h" | |
16 | #include "gdcmTesting.h" | |
17 | ||
15 | 18 | int TestFileMetaInformation(int argc, char *argv[]) |
16 | 19 | { |
17 | (void)argc; | |
18 | (void)argv; | |
20 | std::string dataroot = gdcm::Testing::GetDataRoot(); | |
21 | std::string filename = dataroot + "/012345.002.050.dcm"; | |
22 | ||
23 | gdcm::Reader reader; | |
24 | reader.SetFileName(filename.c_str()); | |
25 | if ( !reader.Read() ) | |
26 | { | |
27 | std::cerr << "Failed to read: " << filename << std::endl; | |
28 | return 1; | |
29 | } | |
30 | ||
31 | const gdcm::File& fi = reader.GetFile(); | |
32 | const gdcm::FileMetaInformation& hd = fi.GetHeader(); | |
33 | ||
34 | std::stringstream ss; | |
35 | hd.Write(ss); | |
36 | gdcm::FileMetaInformation hd2; | |
37 | ||
38 | // FAIL | |
39 | //hd2.Read(ss); | |
40 | ||
41 | // WORKS | |
42 | //ss.ignore(132); | |
43 | //hd2.Read(ss); | |
19 | 44 | |
20 | 45 | return 0; |
21 | 46 | } |
257 | 257 | { |
258 | 258 | return 0; |
259 | 259 | } |
260 | assert( sqi0->GetNumberOfItems() == 1 ); | |
260 | //assert( sqi0->GetNumberOfItems() == 1 ); | |
261 | 261 | for(unsigned int pd = 0; pd < sqi0->GetNumberOfItems(); ++pd) |
262 | 262 | { |
263 | 263 | const gdcm::Item & item0 = sqi0->GetItem(pd+1); // Item start at #1 |
321 | 321 | return 0; |
322 | 322 | } |
323 | 323 | |
324 | assert( sqi0000->GetNumberOfItems() != 1 ); | |
325 | 324 | for(unsigned int pd000 = 0; pd000 < sqi0000->GetNumberOfItems(); ++pd000) |
326 | 325 | { |
327 | 326 | const gdcm::Item & item = sqi0000->GetItem(pd000+1); // Item start at #1 |
489 | 488 | //const gdcm::ByteValue *bv = contourdata.GetByteValue(); |
490 | 489 | gdcm::Attribute<0x3006,0x0042> contgeotype; |
491 | 490 | contgeotype.SetFromDataSet( nestedds2 ); |
492 | assert( contgeotype.GetValue() == "CLOSED_PLANAR " || contgeotype.GetValue() == "POINT " ); | |
491 | assert( contgeotype.GetValue() == "CLOSED_PLANAR " || contgeotype.GetValue() == "POINT " || contgeotype.GetValue() == "OPEN_NONPLANAR" ); | |
493 | 492 | |
494 | 493 | gdcm::Attribute<0x3006,0x0046> numcontpoints; |
495 | 494 | numcontpoints.SetFromDataSet( nestedds2 ); |
502 | 501 | gdcm::Attribute<0x3006,0x0050> at; |
503 | 502 | at.SetFromDataElement( contourdata ); |
504 | 503 | |
505 | if( contgeotype.GetValue() == "CLOSED_PLANAR " ) | |
504 | if( contgeotype.GetValue() == "CLOSED_PLANAR " || contgeotype.GetValue() == "OPEN_NONPLANAR" ) | |
506 | 505 | { |
507 | 506 | // http://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.8.8.6.html |
508 | 507 | if( nestedds2.FindDataElement( gdcm::Tag(0x3006,0x0016) ) ) |
251 | 251 | if(LIBXSLT_XSLTPROC_EXECUTABLE) |
252 | 252 | set(XSLT_PROCESSOR ${LIBXSLT_XSLTPROC_EXECUTABLE}) |
253 | 253 | # http://docbook.sourceforge.net/release/xsl/current/doc/manpages/man.output.quietly.html |
254 | set(XSLT_PROCESSOR_ARG --param man.output.quietly 1) | |
254 | set(XSLT_PROCESSOR_ARG --param man.output.quietly 1 --maxdepth 6000 ) | |
255 | 255 | # User can change the behavior at cmake time: |
256 | 256 | if(NOT DEFINED GDCM_MANPAGES_USE_NONET) |
257 | 257 | set(GDCM_MANPAGES_USE_NONET FALSE) |
8 | 8 | |
9 | 9 | project(${CHARLS_NAMESPACE} CXX) |
10 | 10 | |
11 | if(POLICY CMP0063) | |
12 | cmake_policy(SET CMP0063 NEW) | |
13 | endif() | |
11 | foreach(p | |
12 | CMP0042 | |
13 | CMP0063 | |
14 | ) | |
15 | if(POLICY ${p}) | |
16 | cmake_policy(SET ${p} NEW) | |
17 | endif() | |
18 | endforeach() | |
14 | 19 | |
15 | 20 | #----------------------------------------------------------------------------- |
16 | 21 | # CHARLS version number |
14 | 14 | |
15 | 15 | project(${JPEG_NAMESPACE} C) |
16 | 16 | |
17 | if(POLICY CMP0063) | |
18 | cmake_policy(SET CMP0063 NEW) | |
19 | endif() | |
17 | foreach(p | |
18 | CMP0042 | |
19 | CMP0063 | |
20 | ) | |
21 | if(POLICY ${p}) | |
22 | cmake_policy(SET ${p} NEW) | |
23 | endif() | |
24 | endforeach() | |
20 | 25 | |
21 | 26 | # Do full dependency headers. |
22 | 27 | include_regular_expression("^.*$") |
135 | 135 | #define jzero_far @MANGLE_PREFIX@_jzero_far |
136 | 136 | |
137 | 137 | #define jpeg_memory_src @MANGLE_PREFIX@_memory_src |
138 | #define jpeg_memory_mgr @MANGLE_PREFIX@_memory_mgr | |
139 | #define jpeg_common_struct @MANGLE_PREFIX@_common_struct | |
140 | #define jpeg_error_mgr @MANGLE_PREFIX@_error_mgr | |
141 | #define jpeg_progress_mgr @MANGLE_PREFIX@_progress_mgr | |
142 | #define jpeg_decompress_struct @MANGLE_PREFIX@_decompress_struct | |
143 | #define jpeg_compress_struct @MANGLE_PREFIX@_compress_struct | |
144 | #define jpeg_destination_mgr @MANGLE_PREFIX@_destination_mgr | |
145 | #define jpeg_source_mgr @MANGLE_PREFIX@_source_mgr | |
138 | 146 | |
139 | 147 | #endif |
13 | 13 | if (NOT (${CMAKE_VERSION} VERSION_LESS 3.0)) |
14 | 14 | cmake_policy(SET CMP0042 NEW) |
15 | 15 | endif() |
16 | if(POLICY CMP0063) | |
17 | cmake_policy(SET CMP0063 NEW) | |
18 | endif() | |
16 | ||
17 | foreach(p | |
18 | CMP0042 | |
19 | CMP0063 | |
20 | ) | |
21 | if(POLICY ${p}) | |
22 | cmake_policy(SET ${p} NEW) | |
23 | endif() | |
24 | endforeach() | |
19 | 25 | endif() |
20 | 26 | |
21 | 27 | if(NOT OPENJPEG_NAMESPACE) |
13 | 13 | * nm lib@MANGLE_PREFIX@.a | grep " [RT] " |
14 | 14 | */ |
15 | 15 | |
16 | #define opj_copy_image_header @MANGLE_PREFIX@_opj_copy_image_header | |
16 | 17 | #define opj_create_compress @MANGLE_PREFIX@opj_create_compress |
17 | 18 | #define opj_create_decompress @MANGLE_PREFIX@opj_create_decompress |
18 | 19 | #define opj_decode @MANGLE_PREFIX@opj_decode |
27 | 28 | #define opj_get_cstr_index @MANGLE_PREFIX@opj_get_cstr_index |
28 | 29 | #define opj_get_cstr_info @MANGLE_PREFIX@opj_get_cstr_info |
29 | 30 | #define opj_get_decoded_tile @MANGLE_PREFIX@opj_get_decoded_tile |
31 | #define opj_image_comp_header_update @MANGLE_PREFIX@_opj_image_comp_header_update | |
30 | 32 | #define opj_image_create @MANGLE_PREFIX@opj_image_create |
33 | #define opj_image_create0 @MANGLE_PREFIX@_opj_image_create0 | |
31 | 34 | #define opj_image_destroy @MANGLE_PREFIX@opj_image_destroy |
32 | 35 | #define opj_image_tile_create @MANGLE_PREFIX@opj_image_tile_create |
36 | #define opj_read_bytes_BE @MANGLE_PREFIX@_opj_read_bytes_BE | |
37 | #define opj_read_bytes_LE @MANGLE_PREFIX@_opj_read_bytes_LE | |
38 | #define opj_read_double_BE @MANGLE_PREFIX@_opj_read_double_BE | |
39 | #define opj_read_double_LE @MANGLE_PREFIX@_opj_read_double_LE | |
40 | #define opj_read_float_BE @MANGLE_PREFIX@_opj_read_float_BE | |
41 | #define opj_read_float_LE @MANGLE_PREFIX@_opj_read_float_LE | |
33 | 42 | #define opj_read_header @MANGLE_PREFIX@opj_read_header |
34 | 43 | #define opj_read_tile_header @MANGLE_PREFIX@opj_read_tile_header |
35 | 44 | #define opj_set_decode_area @MANGLE_PREFIX@opj_set_decode_area |
39 | 48 | #define opj_set_error_handler @MANGLE_PREFIX@opj_set_error_handler |
40 | 49 | #define opj_set_info_handler @MANGLE_PREFIX@opj_set_info_handler |
41 | 50 | #define opj_set_MCT @MANGLE_PREFIX@opj_set_MCT |
51 | #define opj_set_warning_handler @MANGLE_PREFIX@opj_set_warning_handler | |
42 | 52 | #define opj_setup_decoder @MANGLE_PREFIX@opj_setup_decoder |
43 | 53 | #define opj_setup_encoder @MANGLE_PREFIX@opj_setup_encoder |
44 | #define opj_set_warning_handler @MANGLE_PREFIX@opj_set_warning_handler | |
45 | 54 | #define opj_start_compress @MANGLE_PREFIX@opj_start_compress |
46 | 55 | #define opj_stream_create @MANGLE_PREFIX@opj_stream_create |
47 | 56 | #define opj_stream_create_default_file_stream @MANGLE_PREFIX@opj_stream_create_default_file_stream |
48 | 57 | #define opj_stream_create_file_stream @MANGLE_PREFIX@opj_stream_create_file_stream |
49 | 58 | #define opj_stream_default_create @MANGLE_PREFIX@opj_stream_default_create |
59 | #define opj_stream_default_read @MANGLE_PREFIX@_opj_stream_default_read | |
60 | #define opj_stream_default_seek @MANGLE_PREFIX@_opj_stream_default_seek | |
61 | #define opj_stream_default_skip @MANGLE_PREFIX@_opj_stream_default_skip | |
62 | #define opj_stream_default_write @MANGLE_PREFIX@_opj_stream_default_write | |
50 | 63 | #define opj_stream_destroy @MANGLE_PREFIX@opj_stream_destroy |
64 | #define opj_stream_flush @MANGLE_PREFIX@_opj_stream_flush | |
65 | #define opj_stream_get_number_byte_left @MANGLE_PREFIX@_opj_stream_get_number_byte_left | |
66 | #define opj_stream_has_seek @MANGLE_PREFIX@_opj_stream_has_seek | |
67 | #define opj_stream_read_data @MANGLE_PREFIX@_opj_stream_read_data | |
68 | #define opj_stream_read_seek @MANGLE_PREFIX@_opj_stream_read_seek | |
69 | #define opj_stream_read_skip @MANGLE_PREFIX@_opj_stream_read_skip | |
70 | #define opj_stream_seek @MANGLE_PREFIX@_opj_stream_seek | |
51 | 71 | #define opj_stream_set_read_function @MANGLE_PREFIX@opj_stream_set_read_function |
52 | 72 | #define opj_stream_set_seek_function @MANGLE_PREFIX@opj_stream_set_seek_function |
53 | 73 | #define opj_stream_set_skip_function @MANGLE_PREFIX@opj_stream_set_skip_function |
54 | 74 | #define opj_stream_set_user_data @MANGLE_PREFIX@opj_stream_set_user_data |
55 | 75 | #define opj_stream_set_user_data_length @MANGLE_PREFIX@opj_stream_set_user_data_length |
56 | 76 | #define opj_stream_set_write_function @MANGLE_PREFIX@opj_stream_set_write_function |
77 | #define opj_stream_skip @MANGLE_PREFIX@_opj_stream_skip | |
78 | #define opj_stream_tell @MANGLE_PREFIX@_opj_stream_tell | |
79 | #define opj_stream_write_data @MANGLE_PREFIX@_opj_stream_write_data | |
80 | #define opj_stream_write_seek @MANGLE_PREFIX@_opj_stream_write_seek | |
81 | #define opj_stream_write_skip @MANGLE_PREFIX@_opj_stream_write_skip | |
57 | 82 | #define opj_version @MANGLE_PREFIX@opj_version |
83 | #define opj_write_bytes_BE @MANGLE_PREFIX@_opj_write_bytes_BE | |
84 | #define opj_write_bytes_LE @MANGLE_PREFIX@_opj_write_bytes_LE | |
85 | #define opj_write_double_BE @MANGLE_PREFIX@_opj_write_double_BE | |
86 | #define opj_write_double_LE @MANGLE_PREFIX@_opj_write_double_LE | |
87 | #define opj_write_float_BE @MANGLE_PREFIX@_opj_write_float_BE | |
88 | #define opj_write_float_LE @MANGLE_PREFIX@_opj_write_float_LE | |
58 | 89 | #define opj_write_tile @MANGLE_PREFIX@opj_write_tile |
59 | 90 | |
60 | 91 | #endif |
8 | 8 | |
9 | 9 | project(${UUID_NAMESPACE} C) |
10 | 10 | |
11 | if(POLICY CMP0063) | |
12 | cmake_policy(SET CMP0063 NEW) | |
13 | endif() | |
11 | foreach(p | |
12 | CMP0042 | |
13 | CMP0063 | |
14 | ) | |
15 | if(POLICY ${p}) | |
16 | cmake_policy(SET ${p} NEW) | |
17 | endif() | |
18 | endforeach() | |
14 | 19 | |
15 | 20 | # Do full dependency headers. |
16 | 21 | include_regular_expression("^.*$") |
0 | 0 | cmake_minimum_required(VERSION 2.8.7) |
1 | if(POLICY CMP0022) | |
2 | cmake_policy(SET CMP0022 NEW) | |
3 | endif() | |
4 | if(POLICY CMP0063) | |
5 | cmake_policy(SET CMP0063 NEW) | |
6 | endif() | |
1 | ||
2 | foreach(p | |
3 | CMP0022 | |
4 | CMP0042 | |
5 | CMP0063 # CMake 3.3.2 | |
6 | ) | |
7 | if(POLICY ${p}) | |
8 | cmake_policy(SET ${p} NEW) | |
9 | endif() | |
10 | endforeach() | |
7 | 11 | |
8 | 12 | # http://www.linuxhacker.at/socketxx |
9 | 13 | if(NOT SOCKETXX_NAMESPACE) |