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;
89  int& num_eles;
90 };
91 
93 bool get_arguments(int argc, char *argv[],
94  char *&input_filename, char *&output_filename,
95  ojph::ui32& skipped_res_for_read,
96  ojph::ui32& skipped_res_for_recon,
97  bool& resilient)
98 {
99  ojph::cli_interpreter interpreter;
100  interpreter.init(argc, argv);
101 
102  ojph::ui32 skipped_res[2] = {0, 0};
103  int num_skipped_res = 0;
104  ui32_list_interpreter ilist(2, num_skipped_res, skipped_res);
105 
106  interpreter.reinterpret("-i", input_filename);
107  interpreter.reinterpret("-o", output_filename);
108  interpreter.reinterpret("-skip_res", &ilist);
109  interpreter.reinterpret("-resilient", resilient);
110 
111  //interpret skipped_string
112  if (num_skipped_res > 0)
113  {
114  skipped_res_for_read = skipped_res[0];
115  if (num_skipped_res > 1)
116  skipped_res_for_recon = skipped_res[1];
117  else
118  skipped_res_for_recon = skipped_res_for_read;
119  }
120 
121  if (interpreter.is_exhausted() == false) {
122  printf("The following arguments were not interpreted:\n");
123  ojph::argument t = interpreter.get_argument_zero();
124  t = interpreter.get_next_avail_argument(t);
125  while (t.is_valid()) {
126  printf("%s\n", t.arg);
127  t = interpreter.get_next_avail_argument(t);
128  }
129  return false;
130  }
131  return true;
132 }
133 
135 const char* get_file_extension(const char* filename)
136 {
137  size_t len = strlen(filename);
138  const char* p = strrchr(filename, '.');
139  if (p == NULL || p == filename + len - 1)
140  OJPH_ERROR(0x01000071,
141  "no file extension is found, or there are no characters "
142  "after the dot \'.\' for filename \"%s\" \n", filename);
143  return p;
144 }
145 
147 int main(int argc, char *argv[]) {
148 
149  char *input_filename = NULL;
150  char *output_filename = NULL;
151  ojph::ui32 skipped_res_for_read = 0;
152  ojph::ui32 skipped_res_for_recon = 0;
153  bool resilient = false;
154 
155  if (argc <= 1) {
156  std::cout <<
157  "\nThe following arguments are necessary:\n"
158  " -i input file name\n"
159 #ifdef OJPH_ENABLE_TIFF_SUPPORT
160  " -o output file name (either pgm, ppm, tif(f), or raw(yuv))\n\n"
161 #else
162  " -o output file name (either pgm, ppm, or raw(yuv))\n\n"
163 #endif // !OJPH_ENABLE_TIFF_SUPPORT
164  "The following arguments are options:\n"
165  " -skip_res x,y a comma-separated list of two elements containing the\n"
166  " number of resolutions to skip. You can specify 1 or 2\n"
167  " parameters; the first specifies the number of resolution\n"
168  " for which data reading is skipped. The second is the\n"
169  " number of skipped resolution for reconstruction, which is\n"
170  " either equal to the first or smaller. If the second is not\n"
171  " specified, it is made to equal to the first.\n"
172  " -resilient true if you want the decoder to be more tolerant of errors\n"
173  " in the codestream\n\n"
174  ;
175  return -1;
176  }
177  if (!get_arguments(argc, argv, input_filename, output_filename,
178  skipped_res_for_read, skipped_res_for_recon,
179  resilient))
180  {
181  return -1;
182  }
183 
184  clock_t begin = clock();
185 
186  try {
187  if (output_filename == NULL)
188  OJPH_ERROR(0x020000008,
189  "Please provide and output file using the -o option\n");
190 
191  ojph::j2c_infile j2c_file;
192  j2c_file.open(input_filename);
193  ojph::codestream codestream;
194 
195  ojph::ppm_out ppm;
196  #ifdef OJPH_ENABLE_TIFF_SUPPORT
197  ojph::tif_out tif;
198  #endif /* OJPH_ENABLE_TIFF_SUPPORT */
199  ojph::yuv_out yuv;
200  ojph::image_out_base *base = NULL;
201  const char *v = get_file_extension(output_filename);
202  if (v)
203  {
204  if (resilient)
205  codestream.enable_resilience();
206  codestream.read_headers(&j2c_file);
207  codestream.restrict_input_resolution(skipped_res_for_read,
208  skipped_res_for_recon);
209  ojph::param_siz siz = codestream.access_siz();
210 
211  if (strncmp(".pgm", v, 4) == 0)
212  {
213 
214  if (siz.get_num_components() != 1)
215  OJPH_ERROR(0x020000001,
216  "The file has more than one color component, but .pgm can "
217  "contain only on color component\n");
218  ppm.configure(siz.get_recon_width(0), siz.get_recon_height(0),
219  siz.get_num_components(), siz.get_bit_depth(0));
220  ppm.open(output_filename);
221  base = &ppm;
222  }
223  else if (strncmp(".ppm", v, 4) == 0)
224  {
225  codestream.set_planar(false);
226  ojph::param_siz siz = codestream.access_siz();
227 
228  if (siz.get_num_components() != 3)
229  OJPH_ERROR(0x020000002,
230  "The file has %d color components; this cannot be saved to"
231  " a .ppm file\n", siz.get_num_components());
232  bool all_same = true;
233  ojph::point p = siz.get_downsampling(0);
234  for (ojph::ui32 i = 1; i < siz.get_num_components(); ++i)
235  {
236  ojph::point p1 = siz.get_downsampling(i);
237  all_same = all_same && (p1.x == p.x) && (p1.y == p.y);
238  }
239  if (!all_same)
240  OJPH_ERROR(0x020000003,
241  "To save an image to ppm, all the components must have the "
242  "downsampling ratio\n");
243  ppm.configure(siz.get_recon_width(0), siz.get_recon_height(0),
244  siz.get_num_components(), siz.get_bit_depth(0));
245  ppm.open(output_filename);
246  base = &ppm;
247  }
248 #ifdef OJPH_ENABLE_TIFF_SUPPORT
249  else if (strncmp(".tif", v, 4) == 0 || strncmp(".tiff", v, 5) == 0)
250  {
251  codestream.set_planar(false);
252  ojph::param_siz siz = codestream.access_siz();
253 
254  bool all_same = true;
255  ojph::point p = siz.get_downsampling(0);
256  for (unsigned int i = 1; i < siz.get_num_components(); ++i)
257  {
258  ojph::point p1 = siz.get_downsampling(i);
259  all_same = all_same && (p1.x == p.x) && (p1.y == p.y);
260  }
261  if (!all_same)
262  OJPH_ERROR(0x020000008,
263  "To save an image to tif(f), all the components must have the "
264  "downsampling ratio\n");
265  ojph::ui32 bit_depths[4] = { 0, 0, 0, 0 };
266  for (ojph::ui32 c = 0; c < siz.get_num_components(); c++)
267  {
268  bit_depths[c] = siz.get_bit_depth(c);
269  }
270  tif.configure(siz.get_recon_width(0), siz.get_recon_height(0),
271  siz.get_num_components(), bit_depths);
272  tif.open(output_filename);
273  base = &tif;
274  }
275 #endif // !OJPH_ENABLE_TIFF_SUPPORT
276  else if (strncmp(".yuv", v, 4) == 0 || strncmp(".raw", v, 4) == 0)
277  {
278  codestream.set_planar(true);
279  ojph::param_siz siz = codestream.access_siz();
280 
281  if (siz.get_num_components() != 3 && siz.get_num_components() != 1)
282  OJPH_ERROR(0x020000004,
283  "The file has %d color components; this cannot be saved to"
284  " .raw(yuv) file\n", siz.get_num_components());
285  ojph::param_cod cod = codestream.access_cod();
286  if (cod.is_using_color_transform())
287  OJPH_ERROR(0x020000005,
288  "The current implementation of raw(yuv) file object does not"
289  " support saving file when conversion from raw(yuv) to rgb is"
290  " needed; in any case, this is not the normal usage of raw(yuv)"
291  "file.");
292  ojph::ui32 comp_widths[3];
293  ojph::ui32 max_bit_depth = 0;
294  for (ojph::ui32 i = 0; i < siz.get_num_components(); ++i)
295  {
296  comp_widths[i] = siz.get_recon_width(i);
297  max_bit_depth = ojph_max(max_bit_depth, siz.get_bit_depth(i));
298  }
299  codestream.set_planar(true);
300  yuv.configure(max_bit_depth, siz.get_num_components(), comp_widths);
301  yuv.open(output_filename);
302  base = &yuv;
303  }
304  else
305 #ifdef OJPH_ENABLE_TIFF_SUPPORT
306  OJPH_ERROR(0x020000006,
307  "unknown output file extension; only pgm, ppm, tif(f) and raw(yuv))"
308  " are supported\n");
309 #else
310  OJPH_ERROR(0x020000006,
311  "unknown output file extension; only pgm, ppm, and raw(yuv) are"
312  " supported\n");
313 #endif // !OJPH_ENABLE_TIFF_SUPPORT
314  }
315  else
316  OJPH_ERROR(0x020000007,
317  "Please supply a proper output filename with a proper extension\n");
318 
319  codestream.create();
320 
321  if (codestream.is_planar())
322  {
323  ojph::param_siz siz = codestream.access_siz();
324  for (ojph::ui32 c = 0; c < siz.get_num_components(); ++c)
325  {
326  ojph::ui32 height = siz.get_recon_height(c);
327  for (ojph::ui32 i = height; i > 0; --i)
328  {
329  ojph::ui32 comp_num;
330  ojph::line_buf *line = codestream.pull(comp_num);
331  assert(comp_num == c);
332  base->write(line, comp_num);
333  }
334  }
335  }
336  else
337  {
338  ojph::param_siz siz = codestream.access_siz();
339  ojph::ui32 height = siz.get_recon_height(0);
340  for (ojph::ui32 i = 0; i < height; ++i)
341  {
342  for (ojph::ui32 c = 0; c < siz.get_num_components(); ++c)
343  {
344  ojph::ui32 comp_num;
345  ojph::line_buf *line = codestream.pull(comp_num);
346  assert(comp_num == c);
347  base->write(line, comp_num);
348  }
349  }
350  }
351 
352  base->close();
353  codestream.close();
354  }
355  catch (const std::exception& e)
356  {
357  const char *p = e.what();
358  if (strncmp(p, "ojph error", 10) != 0)
359  printf("%s\n", p);
360  exit(-1);
361  }
362 
363  clock_t end = clock();
364  double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
365  printf("Elapsed time = %f\n", elapsed_secs);
366 
367  return 0;
368 }
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:308
OJPH_EXPORT 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 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(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[])
const char * get_file_extension(const char *filename)
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:93
#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