OpenJPH
Open-source implementation of JPEG2000 Part-15
Loading...
Searching...
No Matches
test_signed_shift.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: test_signed_shift.cpp
34//***************************************************************************/
35// Round trips of signed images whose samples are negative, through code
36// paths that double a sample. Left-shifting a negative value is undefined
37// behaviour before C++20, so these paths must multiply instead. The tests
38// check that the round trips are exact; built with
39// -fsanitize=shift -fno-sanitize-recover=shift they also check that no
40// negative value is shifted left.
41//
42// * The reversible colour transform (RCT) computes (R + 2G + B) >> 2.
43// The 32 bit path is taken for a bit depth that fits a 32 bit line, and
44// the 64 bit path for a bit depth that does not.
45// * The reversible horizontal analysis of a line that is one sample wide
46// and starts at an odd position doubles that sample.
47//***************************************************************************/
48
49#include <vector>
50
51#include "ojph_mem.h"
52#include "ojph_file.h"
53#include "ojph_codestream.h"
54#include "ojph_params.h"
55#include "gtest/gtest.h"
56
57namespace {
58
60 // Encodes a signed, reversible image held in samples (one vector per
61 // component) into memory, decodes it, and checks that the decoded samples
62 // equal the encoded ones. The image starts at (x_off, 0) so that its
63 // first column can be odd.
65 void round_trip(ojph::ui32 width, ojph::ui32 height, ojph::ui32 num_comps,
66 ojph::ui32 bit_depth, ojph::ui32 x_off,
67 bool color_transform, ojph::ui32 num_decomps,
68 const std::vector<std::vector<ojph::si32> >& samples)
69 {
71 out.open();
72 {
73 ojph::codestream codestream;
74
75 ojph::param_siz siz = codestream.access_siz();
76 siz.set_image_extent(ojph::point(x_off + width, height));
77 siz.set_image_offset(ojph::point(x_off, 0));
78 siz.set_tile_size(ojph::size(x_off + width, height));
80 siz.set_num_components(num_comps);
81 for (ojph::ui32 c = 0; c < num_comps; ++c)
82 siz.set_component(c, ojph::point(1, 1), bit_depth, true);
83
84 ojph::param_cod cod = codestream.access_cod();
85 cod.set_num_decomposition(num_decomps);
86 cod.set_block_dims(64, 64);
87 cod.set_color_transform(color_transform);
88 cod.set_reversible(true);
89
90 codestream.set_planar(false);
91 codestream.write_headers(&out);
92
93 ojph::ui32 next_comp;
94 ojph::line_buf* cur_line = codestream.exchange(NULL, next_comp);
95 for (ojph::ui32 y = 0; y < height; ++y)
96 for (ojph::ui32 c = 0; c < num_comps; ++c)
97 {
98 ASSERT_EQ(next_comp, c);
99 for (ojph::ui32 x = 0; x < width; ++x)
100 cur_line->i32[x] = samples[c][y * width + x];
101 cur_line = codestream.exchange(cur_line, next_comp);
102 }
103 codestream.flush();
104 codestream.close();
105 }
106
108 in.open(out.get_data(), out.get_used_size());
109 {
110 ojph::codestream codestream;
111 codestream.read_headers(&in);
112 codestream.set_planar(false);
113 codestream.create();
114
115 for (ojph::ui32 y = 0; y < height; ++y)
116 for (ojph::ui32 c = 0; c < num_comps; ++c)
117 {
118 ojph::ui32 comp_num;
119 ojph::line_buf* line = codestream.pull(comp_num);
120 ASSERT_EQ(comp_num, c);
121 for (ojph::ui32 x = 0; x < width; ++x)
122 ASSERT_EQ(line->i32[x], samples[c][y * width + x])
123 << "component " << c << " at (" << x << ", " << y << ")";
124 }
125 codestream.close();
126 }
127 }
128
130 // Three components of negative samples; the green component is the most
131 // negative so that 2G is negative whatever R and B are.
133 std::vector<std::vector<ojph::si32> >
134 negative_rgb(ojph::ui32 width, ojph::ui32 height, ojph::si32 scale)
135 {
136 std::vector<std::vector<ojph::si32> > s(3,
137 std::vector<ojph::si32>((size_t)width * height));
138 for (ojph::ui32 i = 0; i < width * height; ++i)
139 {
140 s[0][i] = -scale * (ojph::si32)(i % 7 + 1);
141 s[1][i] = -scale * (ojph::si32)(i % 5 + 8);
142 s[2][i] = -scale * (ojph::si32)(i % 3 + 1);
143 }
144 return s;
145 }
146
147}
148
150// RCT on 32 bit lines, as used for bit depths up to about 30 bits
151TEST(TestSignedShift, RctNegative32) {
152 const ojph::ui32 width = 64, height = 16;
153 round_trip(width, height, 3, 16, 0, true, 5,
154 negative_rgb(width, height, 1000));
155}
156
158// RCT on 64 bit lines, which the library selects for large bit depths
159TEST(TestSignedShift, RctNegative64) {
160 const ojph::ui32 width = 64, height = 16;
161 round_trip(width, height, 3, 32, 0, true, 5,
162 negative_rgb(width, height, 100000000));
163}
164
166// A one sample wide image at an odd horizontal position, so that the single
167// sample is a high-pass sample of the horizontal analysis
168TEST(TestSignedShift, OddSingleColumnNegative) {
169 const ojph::ui32 width = 1, height = 16;
170 std::vector<std::vector<ojph::si32> > s(1,
171 std::vector<ojph::si32>(height));
172 for (ojph::ui32 y = 0; y < height; ++y)
173 s[0][y] = -1000 - (ojph::si32)y;
174 round_trip(width, height, 1, 16, 1, false, 1, s);
175}
176
178int main(int argc, char** argv) {
179 ::testing::InitGoogleTest(&argc, argv);
180 return RUN_ALL_TESTS();
181}
The object represent a codestream.
param_siz access_siz()
Returns the underlying SIZ marker segment object.
param_cod access_cod()
Returns the underlying COD marker segment object.
void close()
Call this function to close the underlying file; works for both encoding and decoding codestreams.
void set_planar(bool planar)
Sets the sequence of pushing or pull rows from the machinery.
line_buf * exchange(line_buf *line, ui32 &next_component)
This call is used to send image data rows to the library. We expect to send one row from a single com...
void read_headers(infile_base *file)
This call reads the headers of a codestream. It is for a reading (or decoding) codestream,...
void write_headers(outfile_base *file, const comment_exchange *comments=NULL, ui32 num_comments=0)
Writes codestream headers when the codestream is used for writing. This function should be called aft...
void create()
This call is for a decoding (or reading) codestream. Call this function after calling restrict_input_...
void flush()
This is the last call to a writing (encoding) codestream. This will write encoded bitstream data to t...
line_buf * pull(ui32 &comp_num)
This call is to pull one row from the codestream, being decoded. The returned line_buf object holds o...
void open(const ui8 *data, size_t size)
mem_outfile stores encoded j2k codestreams in memory
Definition ojph_file.h:127
size_t get_used_size() const
Call this function to get the used size of the memory file.
Definition ojph_file.h:225
void open(size_t initial_size=65536, bool clear_mem=false)
Call this function to open a memory file.
const ui8 * get_data()
Call this function to access memory file data.
Definition ojph_file.h:201
void set_num_decomposition(ui32 num_decompositions)
void set_block_dims(ui32 width, ui32 height)
void set_color_transform(bool color_transform)
void set_reversible(bool reversible)
void set_tile_size(size s)
void set_component(ui32 comp_num, const point &downsampling, ui32 bit_depth, bool is_signed)
void set_num_components(ui32 num_comps)
void set_tile_offset(point offset)
void set_image_offset(point offset)
void set_image_extent(point extent)
int32_t si32
Definition ojph_defs.h:55
uint32_t ui32
Definition ojph_defs.h:54
int main(int argc, char *argv[])
TEST(TestExecutables, OpenJPHCompressNoArguments)