Codebase list gdcm / 766b0df
New upstream version 2.8.9 Gert Wollny 5 years ago
38 changed file(s) with 1863 addition(s) and 1678 deletion(s). Raw diff Collapse all Expand all
5050 reader.SetFileName( filename );
5151 if( !reader.Read() )
5252 {
53 std::cerr << "Could not read : " << filename << std::endl;
53 std::cerr << "Could not read : " << filename;
5454 if( continuemode )
5555 {
56 std::cerr << "Skipping from anonymization process (continue mode)." << std::endl;
56 std::cerr << " -> Skipping from anonymization process (continue mode)." << std::endl;
5757 return true;
5858 }
5959 else
6060 {
61 std::cerr << "Check [--continue] option for skipping files." << std::endl;
61 std::cerr << " -> Check [--continue] option for skipping files." << std::endl;
6262 return false;
6363 }
6464 }
610610 crypto_factory = gdcm::CryptoFactory::GetFactoryInstance(crypto_lib);
611611 if (!crypto_factory)
612612 {
613 std::cerr << "Requested cryptoraphic library not configured." << std::endl;
613 std::cerr << "Requested cryptographic library not configured." << std::endl;
614614 return 1;
615615 }
616616 }
6969 #include <getopt.h>
7070 #include <string.h>
7171
72 #ifndef GDCM_HAVE_ATOLL
7273 #ifdef _MSC_VER
7374 #define atoll _atoi64
75 #else
76 #define atoll atol
77 #endif
7478 #endif
7579
7680 static unsigned int readsize(const char *str, unsigned int * size)
966970
967971 if( gdcm::System::StrCaseCmp(inputextension,".pgm") == 0
968972 || gdcm::System::StrCaseCmp(inputextension,".pnm") == 0
973 || gdcm::System::StrCaseCmp(inputextension,".pbm") == 0
969974 || gdcm::System::StrCaseCmp(inputextension,".ppm") == 0 )
970975 {
971976 gdcm::PNMCodec pnm;
11131118 {
11141119 if( gdcm::System::StrCaseCmp(outputextension,".pgm") == 0
11151120 || gdcm::System::StrCaseCmp(outputextension,".pnm") == 0
1121 || gdcm::System::StrCaseCmp(outputextension,".pbm") == 0
11161122 || gdcm::System::StrCaseCmp(outputextension,".ppm") == 0 )
11171123 {
11181124 gdcm::PNMCodec pnm;
257257 {
258258 Object obj;
259259 const GooString *s1;
260 GBool isUnicode;
260 bool isUnicode;
261261 Unicode u;
262262 char buf[8];
263263 int i, n;
273273 if ((s1->getChar(0) & 0xff) == 0xfe &&
274274 (s1->getChar(1) & 0xff) == 0xff)
275275 {
276 isUnicode = gTrue;
276 isUnicode = true;
277277 i = 2;
278278 }
279279 else
280280 {
281 isUnicode = gFalse;
281 isUnicode = false;
282282 i = 0;
283283 }
284284 while (i < obj.getString()->getLength())
538538 int pages = doc->getNumPages();
539539 const char *encrypted = doc->isEncrypted() ? "yes" : "no";
540540 // 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");
545545
546546 // print linearization info
547547 const char *optimized = doc->isLinearized() ? "yes" : "no";
101101 return out;
102102 }
103103
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)
105105 {
106106 Object obj;
107107 const GooString *s1;
108 GBool isUnicode = gFalse;
108 bool isUnicode = false;
109109 Unicode u;
110110 char buf[8];
111111 int i, n;
121121 if ((s1->getChar(0) & 0xff) == 0xfe &&
122122 (s1->getChar(1) & 0xff) == 0xff)
123123 {
124 isUnicode = gTrue;
124 isUnicode = true;
125125 i = 2;
126126 }
127127 else
128128 {
129 isUnicode = gFalse;
129 isUnicode = false;
130130 i = 0;
131131 }
132132 while (i < obj.getString()->getLength())
397397 std::string creationdate;
398398 std::string moddate;
399399
400 GBool isUnicode = gFalse;
400 bool isUnicode = false;
401401 if (doc->isOk())
402402 {
403403 #ifdef LIBPOPPLER_NEW_OBJECT_API
522522 // construct the target name:
523523 std::string targetname = targetdir;
524524
525 targetdir += "/old/";
525 targetdir += "/old";
526526
527527 // make sure the dir exist first:
528528 if( !gdcm::System::MakeDirectory( targetdir.c_str() ) )
778778 if( !unsorted.empty() )
779779 {
780780 std::string targetdir3 = outfilename;
781 targetdir3 += "/unhandled/";
781 targetdir3 += "/unhandled";
782782 if( !gdcm::System::MakeDirectory( targetdir3.c_str() ) )
783783 {
784 std::cerr << "Could not create dir: " << outfilename << std::endl;
784 std::cerr << "Could not create dir: " << targetdir3 << std::endl;
785785 return 1;
786786 }
787787 std::cerr << "Could not process the following files (please report): " << std::endl;
4242 #----------------------------------------------------------------------------
4343 set(GDCM_MAJOR_VERSION 2)
4444 set(GDCM_MINOR_VERSION 8)
45 set(GDCM_BUILD_VERSION 8)
45 set(GDCM_BUILD_VERSION 9)
4646 set(GDCM_VERSION
4747 "${GDCM_MAJOR_VERSION}.${GDCM_MINOR_VERSION}.${GDCM_BUILD_VERSION}")
4848 # let advanced user the option to define GDCM_API_VERSION:
5050 set(CMAKE_REQUIRED_INCLUDES math.h)
5151 set(CMAKE_REQUIRED_LIBRARIES m)
5252 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)
5357
5458 #include(CheckSymbolExists)
5559 CHECK_FUNCTION_EXISTS(gettimeofday GDCM_HAVE_GETTIMEOFDAY)
116116 #cmakedefine GDCM_HAVE__SNPRINTF
117117 #cmakedefine GDCM_HAVE_LROUND
118118 #cmakedefine GDCM_HAVE_GETTIMEOFDAY
119 #cmakedefine GDCM_HAVE_ATOLL
119120 #cmakedefine GDCM_HAVE_JSON_OBJECT_OBJECT_GET_EX
120121
121122 // MM: I have a feeling that if GDCM_HAVE_WCHAR_IFSTREAM, then UNICODE filename
157157 bool ok = true;
158158 while(ok && (pos = dir.find('/', pos)) != std::string::npos)
159159 {
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()));
162162 pos++;
163163 }
164164 if( !ok ) return false;
2323 #include "gdcmDict.h"
2424 #include "gdcmDictEntry.h"
2525
26 namespace gdcm {
26 namespace {
27 using namespace gdcm;
2728 typedef struct
2829 {
2930 uint16_t group;
1327413275 {0xffff,0xffff,VR::INVALID,VM::VM0,"","",true }, // dummy
1327513276 {0xffff,0xffff,VR::INVALID,VM::VM0,0,0,true } // Gard
1327613277 };
13278 } // end anonymous namespace
13279
13280 namespace gdcm {
1327713281
1327813282 void Dict::LoadDefault()
1327913283 {
2323 #include "gdcmDict.h"
2424 #include "gdcmDictEntry.h"
2525
26 namespace gdcm {
26 namespace {
27 using namespace gdcm;
2728 typedef struct
2829 {
2930 uint16_t group;
1026210263 {0xffff,0xffff,"GDCM Private Sentinel",VR::INVALID,VM::VM0,"",true }, // Dummy invalid element
1026310264 {0xffff,0xffff,"",VR::INVALID,VM::VM0,0,true } // Gard (will NOT be added)
1026410265 };
10266 } //end anonymous namespace
10267 namespace gdcm {
1026510268
1026610269 /*
1026710270 void Dict::LoadDefault()
5353 if( TagField != itemStart )
5454 {
5555 // 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;
5861 }
5962 if( !ValueLengthField.Read<TSwap>(is) )
6063 {
9292 template <typename TSwap>
9393 std::istream& ReadPreValue(std::istream &is)
9494 {
95 //if( SequenceLengthField.IsUndefined() )
9695 // First item is the basic offset table:
96 #if 0
9797 try
9898 {
9999 Table.Read<TSwap>(is);
124124 //assert(0);
125125 }
126126 }
127 #else
128 Table.Read<TSwap>(is);
129 gdcmDebugMacro( "Table: " << Table );
130 #endif
127131 return is;
128132 }
129133
107107 return false;
108108 }
109109
110 return true;//os;
110 return !os.fail();
111111 }
112112
113113 try
158158 Ofstream->close();
159159 }
160160
161 return true;
161 return !os.fail();
162162 }
163163
164164 void Writer::SetFileName(const char *filename)
284284 else if( PF == PixelFormat::SINGLEBIT )
285285 {
286286 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 );
290293 mul = save;
291294 }
292295 else if( PF.GetBitsAllocated() % 8 != 0 )
1717 #include <setjmp.h>
1818
1919 #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"
1818 namespace gdcm
1919 {
2020
21 class JPEGInternals;
21 class JPEGInternals_12BIT;
2222 class ByteValue;
2323 /**
2424 * \brief Class to do JPEG 12bits (lossy & lossless)
4040 virtual bool EncodeBuffer(std::ostream &os, const char *data, size_t datalen);
4141
4242 private:
43 JPEGInternals *Internals;
43 JPEGInternals_12BIT *Internals;
4444 };
4545
4646 } // end namespace gdcm
1717 #include <setjmp.h>
1818
1919 #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"
1818 namespace gdcm
1919 {
2020
21 class JPEGInternals;
21 class JPEGInternals_16BIT;
2222 class ByteValue;
2323 /**
2424 * \brief Class to do JPEG 16bits (lossless)
4040 virtual bool EncodeBuffer(std::ostream &os, const char *data, size_t datalen);
4141
4242 private:
43 JPEGInternals *Internals;
43 JPEGInternals_16BIT *Internals;
4444 };
4545
4646 } // end namespace gdcm
1717 #include <setjmp.h>
1818
1919 #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"
1818 namespace gdcm
1919 {
2020
21 class JPEGInternals;
21 class JPEGInternals_8BIT;
2222 class ByteValue;
2323 /**
2424 * \brief Class to do JPEG 8bits (lossy & lossless)
4040 virtual bool EncodeBuffer(std::ostream &os, const char *data, size_t datalen);
4141
4242 private:
43 JPEGInternals *Internals;
43 JPEGInternals_8BIT *Internals;
4444 };
4545
4646 } // end namespace gdcm
+0
-1592
Source/MediaStorageAndFileFormat/gdcmJPEGBITSCodec.cxx less more
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
185185 if( NumberOfDimensions == 2 )
186186 {
187187 const SequenceOfFragments *sf = in.GetSequenceOfFragments();
188 assert( sf );
188 if (!sf) return false;
189189 unsigned long totalLen = sf->ComputeByteLength();
190190 char *buffer = new char[totalLen];
191191 sf->GetBuffer(buffer, totalLen);
203203 else if( NumberOfDimensions == 3 )
204204 {
205205 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;
208208 std::stringstream os;
209209 for(unsigned int i = 0; i < sf->GetNumberOfFragments(); ++i)
210210 {
211211 const Fragment &frag = sf->GetFragment(i);
212212 if( frag.IsEmpty() ) return false;
213213 const ByteValue *bv = frag.GetByteValue();
214 assert( bv );
214 if (!bv) return false;
215215 size_t totalLen = bv->GetLength();
216216 char *mybuffer = new char[totalLen];
217217
3939 }
4040
4141
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 }
4252
4353 bool PNMCodec::Write(const char *filename, const DataElement &out) const
4454 {
4555 std::ofstream os(filename, std::ios::binary);
4656 const unsigned int *dims = this->GetDimensions();
4757 const PhotometricInterpretation &pi = this->GetPhotometricInterpretation();
58 const PixelFormat& pf = GetPixelFormat();
4859 if( pi == PhotometricInterpretation::MONOCHROME2
4960 || pi == PhotometricInterpretation::MONOCHROME1 ) // warning viz will be surprising
5061 {
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";
5267 }
5368 else if( pi == PhotometricInterpretation::RGB
5469 || pi == PhotometricInterpretation::PALETTE_COLOR )
6984 return false;
7085 }
7186
72 const PixelFormat& pf = GetPixelFormat();
7387 switch(pf)
7488 {
89 case PixelFormat::SINGLEBIT:
90 break;
7591 case PixelFormat::UINT8:
7692 //case PixelFormat::INT8:
77 os << "255";
93 os << "255\n";
7894 break;
7995 case PixelFormat::UINT16:
8096 //case PixelFormat::INT16:
81 os << "65535";
97 os << "65535\n";
8298 break;
8399 default:
84100 gdcmErrorMacro( "Unhandled PF: " << pf );
85101 return false;
86102 }
87 os << "\n";
88103
89104 const ByteValue *bv = out.GetByteValue();
90105 // FIXME: PNM Codec cannot handle encapsulated syntax... sigh
108123 if( pf.GetBitsAllocated() == 16 )
109124 {
110125 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 }
111135 }
112136 else
113137 {
235259 std::string type, str;
236260 std::getline(is,type);
237261 PhotometricInterpretation pi;
238 if( type == "P5" )
262 if( type == "P4" ) // P4 => mono W/B !
263 pi = PhotometricInterpretation::MONOCHROME1;
264 else if( type == "P5" )
239265 pi = PhotometricInterpretation::MONOCHROME2;
240266 else if( type == "P6" ) // P3 => ASCII
241267 pi = PhotometricInterpretation::RGB;
254280 unsigned int dims[3] = {};
255281 is >> dims[0]; is >> dims[1];
256282 unsigned int maxval;
257 is >> maxval;
283 if( type == "P4" )
284 maxval = 1;
285 else
286 is >> maxval;
258287 // http://netpbm.sourceforge.net/doc/pgm.html
259288 // some kind of empty line...
260289 if( is.peek() == '\n' )
265294 //assert(len < INT_MAX);
266295 //assert(pos < INT_MAX);
267296 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 )
269305 {
270306 std::cerr << "Problem computing length" << std::endl;
271307 std::cerr << "Pos: " << len - pos << std::endl;
301337 #else
302338 const int nbits = log2( maxval );
303339 // 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 )
305345 {
306346 pf.SetBitsAllocated( 8 );
307347 pf.SetBitsStored( (unsigned short)nbits );
331371 //image.SetTransferSyntax( TransferSyntax::ExplicitVRBigEndian ); // PGM are big endian
332372 //image.SetTransferSyntax( TransferSyntax::ExplicitVRLittleEndian ); // PGM are big endian
333373 //image.SetTransferSyntax( TransferSyntax::ImplicitVRBigEndianPrivateGE ); // PGM are big endian
334 if( pf.GetBitsAllocated() == 8 )
374 if( pf.GetBitsAllocated() > 8 )
375 ts = TransferSyntax::ImplicitVRBigEndianPrivateGE;
376 else
335377 //ts = TransferSyntax::ImplicitVRLittleEndian; // nicer to handle than private GE
336378 ts = TransferSyntax::ExplicitVRLittleEndian; // nicer to handle than private GE
337 else
338 ts = TransferSyntax::ImplicitVRBigEndianPrivateGE;
339379
340380 SetPhotometricInterpretation( pi );
341381 SetPixelFormat( pf );
296296 b += 3;
297297 }
298298 assert( b == input + length + 2);
299 assert ( pout = output + length );
299 assert ( pout == output + length );
300300 return true;
301301 }
302302
846846 }
847847 //assert( numberOfReadBytes + frame.Header.Offset[i] - is.tellg() + start == 0);
848848 }
849 assert( numOutBytes == length );
849 if( numOutBytes != length ) return false;
850850 }
851851
852852 return ImageCodec::DecodeByStreams(tmpos,os);
6565 { "c6188f2ae06a55d596d4d6b4d914b404f7bf5786" , "D_CLUNIE_RG2_JPLY.dcm" },
6666 { "5035a6298cf8590932605cb4bb10f128df971fcb" , "D_CLUNIE_RG2_RLE.dcm" },
6767 { "d2a56de2e035095c3dea9be80878f9607c63728d" , "D_CLUNIE_RG3_JPLL.dcm" },
68 { "41abc80638b12a2601e7764805a9c4ddc385bdc5" , "D_CLUNIE_RG3_JPLY.dcm" },
68 { "c90b8543259ca7189fa76201f864c2f32e6ebef3" , "D_CLUNIE_RG3_JPLY.dcm" },
6969 { "eb417a88c6b3fe6c5768ab705990fc0d54558816" , "D_CLUNIE_RG3_RLE.dcm" },
7070 { "8e27c853a156038e1f6daebb04f2c9059ebfbd82" , "D_CLUNIE_SC1_JPLY.dcm" },
7171 { "6a6ca811ae87ae1ca4549f49724b58562eea714b" , "D_CLUNIE_SC1_RLE.dcm" },
234234 { "08828e913a7a1ebbc0129c42974b64ce702814b6" , "JPEGNote_missing.dcm" },
235235 { "99c169688190a66100b61319eaeefb3db1936125" , "RLEDebianBug816607Orig.dcm" },
236236 { "f18f91631b59f0242b5daca547878e4c5cbf6a5b" , "GE_MR_0025xx1bProtocolDataBlockXML.dcm" },
237 { "8c46efd571b33264d7c0bed14fb6dd0282330b92" , "JPEGLS_CharLS_10742.dcm" },
237238
238239 { NULL, NULL}
239240 };
4343 std::cerr << "Error" << std::endl;
4444 return 1;
4545 }
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;
4661 return 0;
4762 }
4863
364379 }
365380 int res = 0;
366381 res += TestGetTimeOfDay();
382 res += TestMakeDirectory();
367383
368384 const char * testfilesize = gdcm::Testing::GetTempFilename( "filesize.bin" );
369385 if( gdcm::System::FileExists( testfilesize ) )
1212 =========================================================================*/
1313 #include "gdcmFileMetaInformation.h"
1414
15 #include "gdcmReader.h"
16 #include "gdcmTesting.h"
17
1518 int TestFileMetaInformation(int argc, char *argv[])
1619 {
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);
1944
2045 return 0;
2146 }
257257 {
258258 return 0;
259259 }
260 assert( sqi0->GetNumberOfItems() == 1 );
260 //assert( sqi0->GetNumberOfItems() == 1 );
261261 for(unsigned int pd = 0; pd < sqi0->GetNumberOfItems(); ++pd)
262262 {
263263 const gdcm::Item & item0 = sqi0->GetItem(pd+1); // Item start at #1
321321 return 0;
322322 }
323323
324 assert( sqi0000->GetNumberOfItems() != 1 );
325324 for(unsigned int pd000 = 0; pd000 < sqi0000->GetNumberOfItems(); ++pd000)
326325 {
327326 const gdcm::Item & item = sqi0000->GetItem(pd000+1); // Item start at #1
489488 //const gdcm::ByteValue *bv = contourdata.GetByteValue();
490489 gdcm::Attribute<0x3006,0x0042> contgeotype;
491490 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" );
493492
494493 gdcm::Attribute<0x3006,0x0046> numcontpoints;
495494 numcontpoints.SetFromDataSet( nestedds2 );
502501 gdcm::Attribute<0x3006,0x0050> at;
503502 at.SetFromDataElement( contourdata );
504503
505 if( contgeotype.GetValue() == "CLOSED_PLANAR " )
504 if( contgeotype.GetValue() == "CLOSED_PLANAR " || contgeotype.GetValue() == "OPEN_NONPLANAR" )
506505 {
507506 // http://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.8.8.6.html
508507 if( nestedds2.FindDataElement( gdcm::Tag(0x3006,0x0016) ) )
251251 if(LIBXSLT_XSLTPROC_EXECUTABLE)
252252 set(XSLT_PROCESSOR ${LIBXSLT_XSLTPROC_EXECUTABLE})
253253 # 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 )
255255 # User can change the behavior at cmake time:
256256 if(NOT DEFINED GDCM_MANPAGES_USE_NONET)
257257 set(GDCM_MANPAGES_USE_NONET FALSE)
88
99 project(${CHARLS_NAMESPACE} CXX)
1010
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()
1419
1520 #-----------------------------------------------------------------------------
1621 # CHARLS version number
1414
1515 project(${JPEG_NAMESPACE} C)
1616
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()
2025
2126 # Do full dependency headers.
2227 include_regular_expression("^.*$")
135135 #define jzero_far @MANGLE_PREFIX@_jzero_far
136136
137137 #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
138146
139147 #endif
1313 if (NOT (${CMAKE_VERSION} VERSION_LESS 3.0))
1414 cmake_policy(SET CMP0042 NEW)
1515 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()
1925 endif()
2026
2127 if(NOT OPENJPEG_NAMESPACE)
1313 * nm lib@MANGLE_PREFIX@.a | grep " [RT] "
1414 */
1515
16 #define opj_copy_image_header @MANGLE_PREFIX@_opj_copy_image_header
1617 #define opj_create_compress @MANGLE_PREFIX@opj_create_compress
1718 #define opj_create_decompress @MANGLE_PREFIX@opj_create_decompress
1819 #define opj_decode @MANGLE_PREFIX@opj_decode
2728 #define opj_get_cstr_index @MANGLE_PREFIX@opj_get_cstr_index
2829 #define opj_get_cstr_info @MANGLE_PREFIX@opj_get_cstr_info
2930 #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
3032 #define opj_image_create @MANGLE_PREFIX@opj_image_create
33 #define opj_image_create0 @MANGLE_PREFIX@_opj_image_create0
3134 #define opj_image_destroy @MANGLE_PREFIX@opj_image_destroy
3235 #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
3342 #define opj_read_header @MANGLE_PREFIX@opj_read_header
3443 #define opj_read_tile_header @MANGLE_PREFIX@opj_read_tile_header
3544 #define opj_set_decode_area @MANGLE_PREFIX@opj_set_decode_area
3948 #define opj_set_error_handler @MANGLE_PREFIX@opj_set_error_handler
4049 #define opj_set_info_handler @MANGLE_PREFIX@opj_set_info_handler
4150 #define opj_set_MCT @MANGLE_PREFIX@opj_set_MCT
51 #define opj_set_warning_handler @MANGLE_PREFIX@opj_set_warning_handler
4252 #define opj_setup_decoder @MANGLE_PREFIX@opj_setup_decoder
4353 #define opj_setup_encoder @MANGLE_PREFIX@opj_setup_encoder
44 #define opj_set_warning_handler @MANGLE_PREFIX@opj_set_warning_handler
4554 #define opj_start_compress @MANGLE_PREFIX@opj_start_compress
4655 #define opj_stream_create @MANGLE_PREFIX@opj_stream_create
4756 #define opj_stream_create_default_file_stream @MANGLE_PREFIX@opj_stream_create_default_file_stream
4857 #define opj_stream_create_file_stream @MANGLE_PREFIX@opj_stream_create_file_stream
4958 #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
5063 #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
5171 #define opj_stream_set_read_function @MANGLE_PREFIX@opj_stream_set_read_function
5272 #define opj_stream_set_seek_function @MANGLE_PREFIX@opj_stream_set_seek_function
5373 #define opj_stream_set_skip_function @MANGLE_PREFIX@opj_stream_set_skip_function
5474 #define opj_stream_set_user_data @MANGLE_PREFIX@opj_stream_set_user_data
5575 #define opj_stream_set_user_data_length @MANGLE_PREFIX@opj_stream_set_user_data_length
5676 #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
5782 #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
5889 #define opj_write_tile @MANGLE_PREFIX@opj_write_tile
5990
6091 #endif
88
99 project(${UUID_NAMESPACE} C)
1010
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()
1419
1520 # Do full dependency headers.
1621 include_regular_expression("^.*$")
00 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()
711
812 # http://www.linuxhacker.at/socketxx
913 if(NOT SOCKETXX_NAMESPACE)