OpenJPH
Open-source implementation of JPEG2000 Part-15
ojph_expand.cpp
Go to the documentation of this file.
1//***************************************************************************/
2// This software is released under the 2-Clause BSD license, included
3// below.
4//
5// Copyright (c) 2019, Aous Naman
6// Copyright (c) 2019, Kakadu Software Pty Ltd, Australia
7// Copyright (c) 2019, The University of New South Wales, Australia
8//
9// Redistribution and use in source and binary forms, with or without
10// modification, are permitted provided that the following conditions are
11// met:
12//
13// 1. Redistributions of source code must retain the above copyright
14// notice, this list of conditions and the following disclaimer.
15//
16// 2. Redistributions in binary form must reproduce the above copyright
17// notice, this list of conditions and the following disclaimer in the
18// documentation and/or other materials provided with the distribution.
19//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
26// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31//***************************************************************************/
32// This file is part of the OpenJPH software implementation.
33// File: ojph_expand.cpp
34// Author: Aous Naman
35// Date: 28 August 2019
36//***************************************************************************/
37
38#include <ctime>
39#include <iostream>
40#include <cstdlib>
41
42#include "ojph_arg.h"
43#include "ojph_mem.h"
44#include "ojph_img_io.h"
45#include "ojph_file.h"
46#include "ojph_codestream.h"
47#include "ojph_params.h"
48#include "ojph_message.h"
49
52{
53 ui32_list_interpreter(const int max_num_elements, int& num_elements,
54 ojph::ui32* list)
55 : max_num_eles(max_num_elements), si32list(list), num_eles(num_elements)
56 {}
57
58 virtual void operate(const char *str)
59 {
60 const char *next_char = str;
61 num_eles = 0;
62 do
63 {
64 if (num_eles)
65 {
66 if (*next_char != ',') //separate sizes by a comma
67 throw "sizes in a sizes list must be separated by a comma";
68 next_char++;
69 }
70 char *endptr;
71 si32list[num_eles] = (ojph::ui32)strtoul(next_char, &endptr, 10);
72 if (endptr == next_char)
73 throw "size number is improperly formatted";
74 next_char = endptr;
75 ++num_eles;
76 }
77 while (*next_char == ',' && num_eles < max_num_eles);
78 if (num_eles + 1 < max_num_eles)
79 {
80 if (*next_char)
81 throw "list elements must separated by a "",""";
82 }
83 else if (*next_char)
84 throw "there are too many elements in the size list";
85 }
86
87 const int max_num_eles;
90};
91
93static
94bool get_arguments(int argc, char *argv[],
95 char *&input_filename, char *&output_filename,
96 ojph::ui32& skipped_res_for_read,
97 ojph::ui32& skipped_res_for_recon,
98 bool& resilient)
99{
100 ojph::cli_interpreter interpreter;
101 interpreter.init(argc, argv);
102
103 ojph::ui32 skipped_res[2] = {0, 0};
104 int num_skipped_res = 0;
105 ui32_list_interpreter ilist(2, num_skipped_res, skipped_res);
106
107 interpreter.reinterpret("-i", input_filename);
108 interpreter.reinterpret("-o", output_filename);
109 interpreter.reinterpret("-skip_res", &ilist);
110 interpreter.reinterpret("-resilient", resilient);
111
112 //interpret skipped_string
113 if (num_skipped_res > 0)
114 {
115 skipped_res_for_read = skipped_res[0];
116 if (num_skipped_res > 1)
117 skipped_res_for_recon = skipped_res[1];
118 else
119 skipped_res_for_recon = skipped_res_for_read;
120 }
121
122 if (interpreter.is_exhausted() == false) {
123 printf("The following arguments were not interpreted:\n");
124 ojph::argument t = interpreter.get_argument_zero();
125 t = interpreter.get_next_avail_argument(t);
126 while (t.is_valid()) {
127 printf("%s\n", t.arg);
128 t = interpreter.get_next_avail_argument(t);
129 }
130 return false;
131 }
132 return true;
133}
134
136static
137const char* get_file_extension(const char* filename)
138{
139 size_t len = strlen(filename);
140 const char* p = strrchr(filename, '.');
141 if (p == NULL || p == filename + len - 1)
142 OJPH_ERROR(0x01000071,
143 "no file extension is found, or there are no characters "
144 "after the dot \'.\' for filename \"%s\" \n", filename);
145 return p;
146}
147
149static
150bool is_matching(const char *ref, const char *other)
151{
152 size_t num_ele = strlen(ref);
153
154 if (num_ele != strlen(other))
155 return false;
156
157 for (ojph::ui32 i = 0; i < num_ele; ++i)
158 if (ref[i] != other[i] && ref[i] != tolower(other[i]))
159 return false;
160
161 return true;
162}
163
165int main(int argc, char *argv[]) {
166
167 char *input_filename = NULL;
168 char *output_filename = NULL;
169 ojph::ui32 skipped_res_for_read = 0;
170 ojph::ui32 skipped_res_for_recon = 0;
171 bool resilient = false;
172
173 if (argc <= 1) {
174 std::cout <<
175 "\nThe following arguments are necessary:\n"
176 " -i input file name\n"
177#ifdef OJPH_ENABLE_TIFF_SUPPORT
178 " -o output file name (either pgm, ppm, tif(f), or raw(yuv))\n\n"
179#else
180 " -o output file name (either pgm, ppm, or raw(yuv))\n\n"
181#endif // !OJPH_ENABLE_TIFF_SUPPORT
182 "The following arguments are options:\n"
183 " -skip_res x,y a comma-separated list of two elements containing the\n"
184 " number of resolutions to skip. You can specify 1 or 2\n"
185 " parameters; the first specifies the number of resolution\n"
186 " for which data reading is skipped. The second is the\n"
187 " number of skipped resolution for reconstruction, which is\n"
188 " either equal to the first or smaller. If the second is not\n"
189 " specified, it is made to equal to the first.\n"
190 " -resilient true if you want the decoder to be more tolerant of errors\n"
191 " in the codestream\n\n"
192 ;
193 return -1;
194 }
195 if (!get_arguments(argc, argv, input_filename, output_filename,
196 skipped_res_for_read, skipped_res_for_recon,
197 resilient))
198 {
199 return -1;
200 }
201
202 clock_t begin = clock();
203
204 try {
205 if (output_filename == NULL)
206 OJPH_ERROR(0x020000008,
207 "Please provide and output file using the -o option\n");
208
209 ojph::j2c_infile j2c_file;
210 j2c_file.open(input_filename);
211 ojph::codestream codestream;
212
213 ojph::ppm_out ppm;
214 #ifdef OJPH_ENABLE_TIFF_SUPPORT
215 ojph::tif_out tif;
216 #endif /* OJPH_ENABLE_TIFF_SUPPORT */
217 ojph::yuv_out yuv;
218 ojph::raw_out raw;
219 ojph::image_out_base *base = NULL;
220 const char *v = get_file_extension(output_filename);
221 if (v)
222 {
223 if (resilient)
224 codestream.enable_resilience();
225 codestream.read_headers(&j2c_file);
226 codestream.restrict_input_resolution(skipped_res_for_read,
227 skipped_res_for_recon);
228 ojph::param_siz siz = codestream.access_siz();
229
230 if (is_matching(".pgm", v))
231 {
232
233 if (siz.get_num_components() != 1)
234 OJPH_ERROR(0x020000001,
235 "The file has more than one color component, but .pgm can "
236 "contain only on color component\n");
237 ppm.configure(siz.get_recon_width(0), siz.get_recon_height(0),
238 siz.get_num_components(), siz.get_bit_depth(0));
239 ppm.open(output_filename);
240 base = &ppm;
241 }
242 else if (is_matching(".ppm", v))
243 {
244 codestream.set_planar(false);
245 ojph::param_siz siz = codestream.access_siz();
246
247 if (siz.get_num_components() != 3)
248 OJPH_ERROR(0x020000002,
249 "The file has %d color components; this cannot be saved to"
250 " a .ppm file\n", siz.get_num_components());
251 bool all_same = true;
252 ojph::point p = siz.get_downsampling(0);
253 for (ojph::ui32 i = 1; i < siz.get_num_components(); ++i)
254 {
255 ojph::point p1 = siz.get_downsampling(i);
256 all_same = all_same && (p1.x == p.x) && (p1.y == p.y);
257 }
258 if (!all_same)
259 OJPH_ERROR(0x020000003,
260 "To save an image to ppm, all the components must have the "
261 "downsampling ratio\n");
262 ppm.configure(siz.get_recon_width(0), siz.get_recon_height(0),
263 siz.get_num_components(), siz.get_bit_depth(0));
264 ppm.open(output_filename);
265 base = &ppm;
266 }
267#ifdef OJPH_ENABLE_TIFF_SUPPORT
268 else if (is_matching(".tif", v) || is_matching(".tiff", v))
269 {
270 codestream.set_planar(false);
271 ojph::param_siz siz = codestream.access_siz();
272
273 bool all_same = true;
274 ojph::point p = siz.get_downsampling(0);
275 for (unsigned int i = 1; i < siz.get_num_components(); ++i)
276 {
277 ojph::point p1 = siz.get_downsampling(i);
278 all_same = all_same && (p1.x == p.x) && (p1.y == p.y);
279 }
280 if (!all_same)
281 OJPH_ERROR(0x020000008,
282 "To save an image to tif(f), all the components must have the "
283 "downsampling ratio\n");
284 ojph::ui32 bit_depths[4] = { 0, 0, 0, 0 };
285 for (ojph::ui32 c = 0; c < siz.get_num_components(); c++)
286 {
287 bit_depths[c] = siz.get_bit_depth(c);
288 }
289 tif.configure(siz.get_recon_width(0), siz.get_recon_height(0),
290 siz.get_num_components(), bit_depths);
291 tif.open(output_filename);
292 base = &tif;
293 }
294#endif // !OJPH_ENABLE_TIFF_SUPPORT
295 else if (is_matching(".yuv", v))
296 {
297 codestream.set_planar(true);
298 ojph::param_siz siz = codestream.access_siz();
299
300 if (siz.get_num_components() != 3 && siz.get_num_components() != 1)
301 OJPH_ERROR(0x020000004,
302 "The file has %d color components; this cannot be saved to"
303 " .yuv file\n", siz.get_num_components());
304 ojph::param_cod cod = codestream.access_cod();
305 if (cod.is_using_color_transform())
306 OJPH_ERROR(0x020000005,
307 "The current implementation of yuv file object does not"
308 " support saving file when conversion from yuv to rgb is"
309 " needed; in any case, this is not the normal usage of yuv"
310 "file.");
311 ojph::ui32 comp_widths[3];
312 ojph::ui32 max_bit_depth = 0;
313 for (ojph::ui32 i = 0; i < siz.get_num_components(); ++i)
314 {
315 comp_widths[i] = siz.get_recon_width(i);
316 max_bit_depth = ojph_max(max_bit_depth, siz.get_bit_depth(i));
317 }
318 codestream.set_planar(true);
319 yuv.configure(max_bit_depth, siz.get_num_components(), comp_widths);
320 yuv.open(output_filename);
321 base = &yuv;
322 }
323 else if (is_matching(".raw", v))
324 {
325 ojph::param_siz siz = codestream.access_siz();
326
327 if (siz.get_num_components() != 1)
328 OJPH_ERROR(0x020000006,
329 "The file has %d color components; this cannot be saved to"
330 " .raw file (only one component is allowed).\n",
331 siz.get_num_components());
332 bool is_signed = siz.is_signed(0);
333 ojph::ui32 width = siz.get_recon_width(0);
334 ojph::ui32 bit_depth = siz.get_bit_depth(0);
335 raw.configure(is_signed, bit_depth, width);
336 raw.open(output_filename);
337 base = &raw;
338 }
339 else
340#ifdef OJPH_ENABLE_TIFF_SUPPORT
341 OJPH_ERROR(0x020000007,
342 "unknown output file extension; only pgm, ppm, tif(f) and raw(yuv))"
343 " are supported\n");
344#else
345 OJPH_ERROR(0x020000006,
346 "unknown output file extension; only pgm, ppm, and raw(yuv) are"
347 " supported\n");
348#endif // !OJPH_ENABLE_TIFF_SUPPORT
349 }
350 else
351 OJPH_ERROR(0x020000007,
352 "Please supply a proper output filename with a proper extension\n");
353
354 codestream.create();
355
356 if (codestream.is_planar())
357 {
358 ojph::param_siz siz = codestream.access_siz();
359 for (ojph::ui32 c = 0; c < siz.get_num_components(); ++c)
360 {
361 ojph::ui32 height = siz.get_recon_height(c);
362 for (ojph::ui32 i = height; i > 0; --i)
363 {
364 ojph::ui32 comp_num;
365 ojph::line_buf *line = codestream.pull(comp_num);
366 assert(comp_num == c);
367 base->write(line, comp_num);
368 }
369 }
370 }
371 else
372 {
373 ojph::param_siz siz = codestream.access_siz();
374 ojph::ui32 height = siz.get_recon_height(0);
375 for (ojph::ui32 i = 0; i < height; ++i)
376 {
377 for (ojph::ui32 c = 0; c < siz.get_num_components(); ++c)
378 {
379 ojph::ui32 comp_num;
380 ojph::line_buf *line = codestream.pull(comp_num);
381 assert(comp_num == c);
382 base->write(line, comp_num);
383 }
384 }
385 }
386
387 base->close();
388 codestream.close();
389 }
390 catch (const std::exception& e)
391 {
392 const char *p = e.what();
393 if (strncmp(p, "ojph error", 10) != 0)
394 printf("%s\n", p);
395 exit(-1);
396 }
397
398 clock_t end = clock();
399 double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
400 printf("Elapsed time = %f\n", elapsed_secs);
401
402 return 0;
403}
bool is_valid()
Definition: ojph_arg.h:58
char * arg
Definition: ojph_arg.h:57
void init(int argc, char *argv[])
Definition: ojph_arg.h:73
void reinterpret(const char *str, int &val)
Definition: ojph_arg.h:146
argument get_argument_zero()
Definition: ojph_arg.h:126
argument get_next_avail_argument(const argument &arg)
Definition: ojph_arg.h:133
OJPH_EXPORT param_siz access_siz()
OJPH_EXPORT param_cod access_cod()
OJPH_EXPORT void restrict_input_resolution(ui32 skipped_res_for_data, ui32 skipped_res_for_recon)
OJPH_EXPORT void close()
OJPH_EXPORT void set_planar(bool planar)
OJPH_EXPORT void enable_resilience()
OJPH_EXPORT void read_headers(infile_base *file)
OJPH_EXPORT void create()
OJPH_EXPORT bool is_planar() const
OJPH_EXPORT line_buf * pull(ui32 &comp_num)
virtual ui32 write(const line_buf *line, ui32 comp_num)=0
virtual void close()
Definition: ojph_img_io.h:518
void open(const char *filename)
Definition: ojph_file.cpp:181
OJPH_EXPORT bool is_using_color_transform() const
OJPH_EXPORT ui32 get_bit_depth(ui32 comp_num) const
OJPH_EXPORT ui32 get_recon_height(ui32 comp_num) const
OJPH_EXPORT point get_downsampling(ui32 comp_num) const
OJPH_EXPORT ui32 get_recon_width(ui32 comp_num) const
OJPH_EXPORT bool is_signed(ui32 comp_num) const
OJPH_EXPORT ui32 get_num_components() const
void open(char *filename)
void configure(ui32 width, ui32 height, ui32 num_components, ui32 bit_depth)
void open(char *filename)
void configure(bool is_signed, ui32 bit_depth, ui32 width)
void open(char *filename)
void configure(ui32 bit_depth, ui32 num_components, ui32 *comp_width)
uint32_t ui32
Definition: ojph_defs.h:54
#define ojph_max(a, b)
Definition: ojph_defs.h:73
int main(int argc, char *argv[])
static const char * get_file_extension(const char *filename)
static bool get_arguments(int argc, char *argv[], char *&input_filename, char *&output_filename, ojph::ui32 &skipped_res_for_read, ojph::ui32 &skipped_res_for_recon, bool &resilient)
Definition: ojph_expand.cpp:94
static bool is_matching(const char *ref, const char *other)
#define OJPH_ERROR(t,...)
Definition: ojph_message.h:131
virtual void operate(const char *str)
Definition: ojph_expand.cpp:58
ui32_list_interpreter(const int max_num_elements, int &num_elements, ojph::ui32 *list)
Definition: ojph_expand.cpp:53
ojph::ui32 * si32list
Definition: ojph_expand.cpp:88
const ojph::ui32 max_num_eles