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
17using namespace std;
18
19#if ENABLEJP2K
20using namespace kdu_core;
21using namespace kdu_supp;
22#endif
23
24namespace 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
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
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
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 exception class.
Definition IException.h:91
@ Programmer
This error is for when a programmer made an API call that was illegal.
Definition IException.h:146
std::vector< unsigned int > p_precinctSize
Precinct size(s) used to create output file.
Definition JP2Encoder.h:91
QString p_jp2File
Output file name.
Definition JP2Encoder.h:89
~JP2Encoder()
JP2Encoder destructor.
void OpenFile()
Open the JPEG2000 file and initialize it.
JP2Encoder(const QString &jp2file, const unsigned int nsamps, const unsigned int nlines, const unsigned int nbands, const Isis::PixelType type)
Constructs a JPEG2000 encoder object.
void Write(unsigned char **inbuf)
Write 8-bit data to JP2 file.
std::string p_progressionOrder
Progression order used to create output file.
Definition JP2Encoder.h:90
JP2Error * Kakadu_Error
JP2 Error handling facility.
Definition JP2Encoder.h:92
Kakadu error messaging class.
Definition JP2Error.h:38
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
PixelType
Enumerations for Isis Pixel Types.
Definition PixelType.h:27
Namespace for the standard library.