Isis 3 Programmer Reference
JP2Encoder.cpp
1 
6 /* SPDX-License-Identifier: CC0-1.0 */
7 #include <float.h>
8 #include <iostream>
9 #include <string>
10 #include <sstream>
11 
12 #include "IException.h"
13 #include "IString.h"
14 #include "JP2Encoder.h"
15 #include "JP2Error.h"
16 
17 using namespace std;
18 
19 #if ENABLEJP2K
20 using namespace kdu_core;
21 using namespace kdu_supp;
22 #endif
23 
24 namespace Isis {
25 
36  JP2Encoder::JP2Encoder(const QString &jp2file, const unsigned int nsamps,
37  const unsigned int nlines, const unsigned int nbands,
38  const Isis::PixelType type) {
39 
40 #if ENABLEJP2K
41  p_jp2File = jp2file;
42  p_sampleDimension = nsamps;
43  p_lineDimension = nlines;
44  p_bandDimension = nbands;
45 
46  if(p_sampleDimension == 0 || p_lineDimension == 0 || p_bandDimension == 0) {
47  string msg = "Invalid sample/line/band dimensions specified for output file";
48  throw IException(IException::Programmer, msg, _FILEINFO_);
49  }
50 
51  if(type == Isis::SignedWord) {
52  p_signedData = true;
53  p_pixelBits = 16;
54  p_pixelBytes = 2;
55  }
56  else if(type == Isis::UnsignedWord) {
57  p_signedData = false;
58  p_pixelBits = 16;
59  p_pixelBytes = 2;
60  }
61  else if(type == Isis::UnsignedByte) {
62  p_signedData = false;
63  p_pixelBits = 8;
64  p_pixelBytes = 1;
65  }
66  else {
67  string msg = "Invalid pixel type specified for output file";
68  throw IException(IException::Programmer, msg, _FILEINFO_);
69  }
70 
71  // Determine number of resolution levels. The sample/line dimension at the
72  // smallest resolution must not be smaller than 64. The number of resolution
73  // levels must not exceed 32.
74  p_resolutionLevels = 1;
75  int mindim =
76  (p_sampleDimension > p_lineDimension) ? p_lineDimension : p_sampleDimension;
77  while(mindim > 64 && p_resolutionLevels < 32) {
78  ++p_resolutionLevels;
79  mindim >>= 1;
80  }
81 
82  // Precinct size will be set to 256 for all resolution levels
83  p_precinctSize.resize(p_resolutionLevels, 256);
84 
85  // The progression order, code block size, and tile size are all set to
86  // values that allow incremental flushing to work. Incremental flushing
87  // prevents us from having to store the entire compressed codestream in
88  // memory before writing it to disk.
89  p_progressionOrder = "PCRL";
90  p_codeBlockSize = 64;
91  p_tileSizeWidth = p_sampleDimension; // untiled - size of image
92  p_tileSizeHeight = p_lineDimension;
93 
94  // Register the Kakadu error handler
95  Kakadu_Error = new JP2Error;
96  kdu_customize_errors(Kakadu_Error);
97 #else
98  std::string msg = "JPEG2000 has not been enabled with this build of ISIS3";
99  throw IException(IException::Programmer, msg, _FILEINFO_);
100 #endif
101  }
102 
103 
108  void JP2Encoder::OpenFile() {
109 #if ENABLEJP2K
110  // Open the JP2 file stream
111  JP2_Stream = new jp2_family_tgt();
112  JP2_Stream->open(p_jp2File.toLatin1().data());
113 
114  // Open the JP2 boxes
115  JP2_Boxes = new jp2_target();
116  JP2_Boxes->open(JP2_Stream);
117 
118  // Configure and write all required JP2 boxes up to, but not including,
119  // the JPEG2000 codestream (jp2c) box. This includes the Signature,
120  // File_Type, and JP2_Header boxes with the latter including the
121  // Image_Header and Colour_Specification subboxes.
122 
123  // Set the codestream SIZ parameters - this includes the image data
124  // organization, resolution levels, reversible (lossless) discrete
125  // wavelet transform, and encoding progression order.
126  siz_params *codestream_parameters = new siz_params();
127  codestream_parameters->set(Sdims, 0, 0, (int)p_lineDimension);
128  codestream_parameters->set(Sdims, 0, 1, (int)p_sampleDimension);
129  codestream_parameters->set(Sprecision, 0, 0, (int)p_pixelBits);
130  codestream_parameters->set(Stiles, 0, 0, (int)p_tileSizeHeight);
131  codestream_parameters->set(Stiles, 0, 1, (int)p_tileSizeWidth);
132  codestream_parameters->set(Ssigned, 0, 0, p_signedData);
133  codestream_parameters->set(Scomponents, 0, 0, (int)p_bandDimension);
134  ostringstream levels;
135  levels << "Clevels=" << (p_resolutionLevels - 1);
136  codestream_parameters->parse_string(levels.str().c_str());
137  codestream_parameters->parse_string("Creversible=yes");
138  string progression = "Corder=" + p_progressionOrder;
139  codestream_parameters->parse_string(progression.c_str());
140 
141  // Determine the number of tile length marker segments. This is
142  // necessary if incremental flushing of the codestream is to be
143  // employed. Incremental flushing prevents the software from
144  // having to store the entire codestream in memory before writing
145  // it to disk. The number of tile length marker segments is
146  // estimated by dividing the tile height by the number of lines
147  // requested for incremental flushing rounded up to the next whole
148  // number.
149  int TLM_segments;
150  int p_flushLines = 0;
151  long long line_bytes = (long long)p_sampleDimension * p_pixelBytes;
152  if(INCREMENTAL_FLUSH_BYTES < (p_lineDimension * line_bytes)) {
153  p_flushLines = p_tileSizeHeight;
154  while((p_flushLines * line_bytes) > INCREMENTAL_FLUSH_BYTES) {
155  p_flushLines -= 1024;
156  if(p_flushLines < 0) p_flushLines = 0;
157  }
158  }
159  if(p_flushLines) {
160  TLM_segments = (int)(((double)p_tileSizeHeight / (double)p_flushLines) + 0.5);
161  if(!TLM_segments) TLM_segments = 1;
162  }
163  else {
164  TLM_segments = 1;
165  }
166 
167  ostringstream segments;
168  segments << "ORGgen_tlm=" << TLM_segments;
169  codestream_parameters->parse_string(segments.str().c_str());
170 
171  // Include packet length markers in tile headers
172  codestream_parameters->parse_string("ORGgen_plt=yes");
173 
174  // Finalize the codestream parameters
175  codestream_parameters->finalize_all();
176 
177  // Construct the JPEG2000 codestream object
178  JPEG2000_Codestream = new kdu_codestream();
179  JPEG2000_Codestream->create(codestream_parameters, JP2_Boxes);
180 
181  // Some parameters must be set again after creating the codestream.
182  // It was not clear if they need to be set twice or only after
183  // creating the codestream.
184  codestream_parameters = JPEG2000_Codestream->access_siz();
185  codestream_parameters->parse_string(levels.str().c_str());
186  codestream_parameters->parse_string("Creversible=yes");
187  codestream_parameters->parse_string(progression.c_str());
188  codestream_parameters->parse_string(segments.str().c_str());
189  codestream_parameters->parse_string("ORGgen_plt=yes");
190 
191  // Set precinct sizes - vertical dimension gets set first. In our
192  // case, both dimensions are the same.
193  ostringstream sizes;
194  sizes << "Cprecincts=";
195  for(unsigned int i = 0; i < p_precinctSize.size(); i++) {
196  if(i != 0) sizes << ",";
197  sizes << "{" << p_precinctSize[i] << "," << p_precinctSize[i] << "}";
198  }
199  codestream_parameters->parse_string(sizes.str().c_str());
200 
201  // Set code block size - vertical dimension gets set first. In our
202  // case, both dimensions are the same.
203  ostringstream size;
204  size << "Cblk={" << p_codeBlockSize << "," << p_codeBlockSize << "}";
205  codestream_parameters->parse_string(size.str().c_str());
206 
207  codestream_parameters->finalize_all();
208 
209  // Finalize image dimensions
210  jp2_dimensions dimensions = JP2_Boxes->access_dimensions();
211  dimensions.init(codestream_parameters);
212  dimensions.finalize_compatibility(codestream_parameters);
213 
214  // Set colour definition
215  jp2_colour colour = JP2_Boxes->access_colour();
216  colour.init((p_bandDimension >= 3) ? JP2_sRGB_SPACE : JP2_sLUM_SPACE);
217 
218  // Write all JP2 boxes up to, but not including, the codestream box
219  JP2_Boxes->write_header();
220 
221  // Initialize the encoder
222  // Open the JPEG2000 codestream (jp2c) box
223  JP2_Boxes->open_codestream();
224 
225  // Set number of quality layers to 1
226  int layers;
227  kdu_params *COD = JPEG2000_Codestream->access_siz()->access_cluster(COD_params);
228  if(!(COD->get(Clayers, 0, 0, layers) && (layers > 0)))
229  COD->set(Clayers, 0, 0, layers = 1);
230  kdu_long *layer_sizes = new kdu_long[layers];
231  memset(layer_sizes, 0, sizeof(kdu_long)*layers);
232 
233  // Initialize the codestream stripe compressor
234  p_compressor.start(*JPEG2000_Codestream, layers, layer_sizes, NULL, 0, false,
235  p_pixelBytes == 4); // Force precise for 32-bit values
236 
237  // Determine optimum stripe heights for accessing data
238  p_stripeHeights = new int[p_bandDimension];
239  p_maxStripeHeights = new int[p_bandDimension];
240  p_precisions = new int[p_bandDimension];
241  p_isSigned = new bool[p_bandDimension];
242  p_compressor.get_recommended_stripe_heights(MIN_STRIPE_HEIGHT,
243  MAX_STRIPE_HEIGHT, p_stripeHeights, p_maxStripeHeights);
244  for(unsigned int i = 0; i < p_bandDimension; i++) {
245  p_precisions[i] = p_pixelBits;
246  p_isSigned[i] = p_signedData;
247  p_stripeHeights[i] = 1;
248  }
249 #endif
250  }
251 
260  void JP2Encoder::Write(unsigned char **inbuf) {
261 #if ENABLEJP2K
262  p_writeStripes = p_compressor.push_stripe(inbuf, p_stripeHeights, NULL, NULL,
263  p_precisions, p_flushLines);
264 #endif
265  }
266 
275  void JP2Encoder::Write(short int **inbuf) {
276 #if ENABLEJP2K
277  p_writeStripes = p_compressor.push_stripe(inbuf, p_stripeHeights, NULL, NULL,
278  p_precisions, p_isSigned, p_flushLines);
279 #endif
280  }
281 
286  JP2Encoder::~JP2Encoder() {
287 #if ENABLEJP2K
288  p_compressor.finish();
289  JPEG2000_Codestream->destroy();
290  JP2_Boxes->close();
291  JP2_Stream->close();
292  delete [] p_stripeHeights;
293  delete [] p_maxStripeHeights;
294  delete [] p_precisions;
295  delete [] p_isSigned;
296 #endif
297  }
298 }
Isis::JP2Error
Kakadu error messaging class.
Definition: JP2Error.h:38
Isis::IException
Isis exception class.
Definition: IException.h:91
Isis::PixelType
PixelType
Enumerations for Isis Pixel Types.
Definition: PixelType.h:27
std
Namespace for the standard library.
Isis
This is free and unencumbered software released into the public domain.
Definition: Apollo.h:16