OpenJPH
Open-source implementation of JPEG2000 Part-15
Loading...
Searching...
No Matches
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
93bool 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
135const 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
147int 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
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()
OJPH_EXPORT void open(const char *filename)
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)
#define OJPH_ERROR(t,...)
virtual void operate(const char *str)
ui32_list_interpreter(const int max_num_elements, int &num_elements, ojph::ui32 *list)
const ojph::ui32 max_num_eles