Skip to content

Commit

Permalink
Add support for 32-bit and sub-sampling
Browse files Browse the repository at this point in the history
  • Loading branch information
palemieux committed Dec 13, 2024
1 parent a1e1945 commit 2a3f1c5
Show file tree
Hide file tree
Showing 5 changed files with 278 additions and 75 deletions.
2 changes: 1 addition & 1 deletion cmake/OpenEXRSetup.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ include(FetchContent)
FetchContent_Declare(
openjph
GIT_REPOSITORY https://github.com/aous72/OpenJPH
GIT_TAG origin/master
GIT_TAG 0.18.2
)

FetchContent_MakeAvailable(openjph)
Expand Down
292 changes: 241 additions & 51 deletions src/lib/OpenEXRCore/internal_ht.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
** Copyright Contributors to the OpenEXR Project.
*/

#include <fstream>

#include "internal_compress.h"
#include "internal_decompress.h"

Expand Down Expand Up @@ -32,8 +34,8 @@ internal_exr_undo_ht (
{
exr_result_t rv = EXR_ERR_SUCCESS;

std::vector<int> cs_to_file_ch (decode->channel_count);
bool isRGB = make_channel_map (
std::vector<CodestreamChannelInfo> cs_to_file_ch (decode->channel_count);
bool isRGB = make_channel_map (
decode->channel_count, decode->channels, cs_to_file_ch);

ojph::mem_infile infile;
Expand All @@ -44,41 +46,131 @@ internal_exr_undo_ht (
cs.read_headers (&infile);

ojph::param_siz siz = cs.access_siz ();
ojph::ui32 width = siz.get_image_extent ().x - siz.get_image_offset ().x;
ojph::ui32 height = siz.get_image_extent ().y - siz.get_image_offset ().y;
ojph::param_nlt nlt = cs.access_nlt ();

assert (decode->chunk.width == width);
assert (decode->chunk.height == height);
assert (decode->channel_count == siz.get_num_components ());
ojph::ui32 image_width =
siz.get_image_extent ().x - siz.get_image_offset ().x;
ojph::ui32 image_height =
siz.get_image_extent ().y - siz.get_image_offset ().y;

assert (decode->channel_count * 2 * width * height == uncompressed_size);
int bpl = 0;
bool is_planar = false;
for (ojph::ui32 c = 0; c < decode->channel_count; c++)
{
bpl +=
decode->channels[c].bytes_per_element * decode->channels[c].width;
if (decode->channels[c].x_samples > 1 ||
decode->channels[c].y_samples > 1)
{ is_planar = true; }
}
cs.set_planar (is_planar);

cs.set_planar (false);
assert (decode->chunk.width == image_width);
assert (decode->chunk.height == image_height);
assert (decode->channel_count == siz.get_num_components ());

cs.create ();

assert (sizeof (int16_t) == 2);
int16_t* line_pixels = static_cast<int16_t*> (uncompressed_data);

for (uint32_t i = 0; i < height; ++i)
assert (sizeof (uint16_t) == 2);
assert (sizeof (uint32_t) == 4);
ojph::ui32 next_comp = 0;
ojph::line_buf* cur_line;
if (cs.is_planar ())
{

for (uint32_t c = 0; c < decode->channel_count; c++)
{
ojph::ui32 next_comp = 0;
ojph::line_buf* cur_line = cs.pull (next_comp);
int file_c = cs_to_file_ch[c].file_index;
assert (
siz.get_recon_height (c) == decode->channels[file_c].height);
assert (decode->channels[file_c].width == siz.get_recon_width (c));

assert (next_comp == c);
if (decode->channels[file_c].height == 0) continue;

int16_t* channel_pixels = line_pixels + width * cs_to_file_ch[c];
uint8_t* line_pixels = static_cast<uint8_t*> (uncompressed_data);

for (uint32_t p = 0; p < width; p++)
for (int64_t y = decode->chunk.start_y;
y < image_height + decode->chunk.start_y;
y++)
{
*channel_pixels++ = (int16_t) (cur_line->i32[p]);
for (ojph::ui32 line_c = 0; line_c < decode->channel_count;
line_c++)
{
if (y % decode->channels[line_c].y_samples != 0) continue;

if (line_c == file_c)
{
cur_line = cs.pull (next_comp);
assert (next_comp == c);

if (decode->channels[file_c].data_type ==
EXR_PIXEL_HALF)
{
int16_t* channel_pixels = (int16_t*) line_pixels;
for (uint32_t p = 0;
p < decode->channels[file_c].width;
p++)
{
*channel_pixels++ = cur_line->i32[p];
// assert (*(channel_pixels - 1) == 0);
}
}
else
{
int32_t* channel_pixels = (int32_t*) line_pixels;
for (uint32_t p = 0;
p < decode->channels[file_c].width;
p++)
{
*channel_pixels++ = cur_line->i32[p];
// assert (*(channel_pixels - 1) == 0);
}
}
}

line_pixels += decode->channels[line_c].bytes_per_element *
decode->channels[line_c].width;
}
}
}
}
else
{
uint8_t* line_pixels = static_cast<uint8_t*> (uncompressed_data);

line_pixels += width * decode->channel_count;
assert (bpl * image_height == uncompressed_size);

for (uint32_t y = 0; y < image_height; ++y)
{
for (uint32_t c = 0; c < decode->channel_count; c++)
{
int file_c = cs_to_file_ch[c].file_index;
cur_line = cs.pull (next_comp);
assert (next_comp == c);
if (decode->channels[file_c].data_type == EXR_PIXEL_HALF)
{
int16_t* channel_pixels =
(int16_t*) (line_pixels + cs_to_file_ch[c].raster_line_offset);
for (uint32_t p = 0; p < decode->channels[file_c].width;
p++)
{
*channel_pixels++ = cur_line->i32[p];
// assert (*(channel_pixels - 1) == 0);
}
}
else
{
int32_t* channel_pixels =
(int32_t*) (line_pixels + cs_to_file_ch[c].raster_line_offset);
for (uint32_t p = 0; p < decode->channels[file_c].width;
p++)
{
*channel_pixels++ = cur_line->i32[p];
// assert (*(channel_pixels - 1) == 0);
}
}
}
line_pixels += bpl;
}
}

infile.close ();
Expand All @@ -91,71 +183,162 @@ internal_exr_apply_ht (exr_encode_pipeline_t* encode)
{
exr_result_t rv = EXR_ERR_SUCCESS;

std::vector<int> cs_to_file_ch(encode->channel_count);
bool isRGB = make_channel_map (
std::vector<CodestreamChannelInfo> cs_to_file_ch (encode->channel_count);
bool isRGB = make_channel_map (
encode->channel_count, encode->channels, cs_to_file_ch);

int height = encode->channels[0].height;
int width = encode->channels[0].width;
int image_height = encode->chunk.height;
int image_width = encode->chunk.width;

ojph::codestream cs;
cs.set_planar (false);

ojph::param_siz siz = cs.access_siz ();
ojph::param_nlt nlt = cs.access_nlt ();

bool isPlanar = false;
siz.set_num_components (encode->channel_count);
int bpl = 0;
for (ojph::ui32 c = 0; c < encode->channel_count; c++)
siz.set_component (c, ojph::point (1, 1), 16, true);
{
int file_c = cs_to_file_ch[c].file_index;
nlt.set_type3_transformation (
c, encode->channels[file_c].data_type != EXR_PIXEL_UINT);

siz.set_component (
c,
ojph::point (
encode->channels[file_c].x_samples,
encode->channels[file_c].y_samples),
encode->channels[file_c].data_type == EXR_PIXEL_HALF ? 16 : 32,
encode->channels[file_c].data_type != EXR_PIXEL_UINT);

if (encode->channels[file_c].x_samples > 1 ||
encode->channels[file_c].y_samples > 1)
{ isPlanar = true; }

// std::cout << " Component number, color, bitdepth: " << c << ", " << encode->channels[file_c].channel_name << ", " << siz.get_bit_depth(c) << std::endl;

bpl += encode->channels[file_c].bytes_per_element *
encode->channels[file_c].width;
}

cs.set_planar (isPlanar);

siz.set_image_offset (ojph::point (0, 0));
siz.set_tile_offset (ojph::point (0, 0));
siz.set_image_extent (ojph::point (width, height));
siz.set_tile_size (ojph::size (width, height));
siz.set_image_extent (ojph::point (image_width, image_height));

ojph::param_cod cod = cs.access_cod ();

cod.set_color_transform (isRGB);
cod.set_color_transform (isRGB && !isPlanar);
cod.set_reversible (true);
cod.set_block_dims (128, 32);
cod.set_num_decomposition (5);

ojph::param_nlt nlt = cs.access_nlt();
nlt.set_type3_transformation(65535, true);

ojph::mem_outfile output;

output.open ();

cs.write_headers (&output);

assert (
encode->packed_bytes == (encode->channel_count * 2 * height * width));

const int16_t* line_pixels =
static_cast<const int16_t*> (encode->packed_buffer);
ojph::ui32 next_comp = 0;
ojph::line_buf* cur_line = cs.exchange (NULL, next_comp);

for (ojph::ui32 i = 0; i < height; ++i)
if (cs.is_planar ())
{
const char* in_buf;

for (ojph::ui32 c = 0; c < encode->channel_count; c++)
{
assert (next_comp == c);
if (encode->channels[c].height == 0) continue;

const int16_t* channel_pixels =
line_pixels + width * cs_to_file_ch[c];
const uint8_t* line_pixels =
static_cast<const uint8_t*> (encode->packed_buffer);
int file_c = cs_to_file_ch[c].file_index;

for (uint32_t p = 0; p < width; p++)
for (int64_t y = encode->chunk.start_y;
y < image_height + encode->chunk.start_y;
y++)
{
cur_line->i32[p] = static_cast<const ojph::si32> (*channel_pixels++);
for (ojph::ui32 line_c = 0; line_c < encode->channel_count;
line_c++)
{

if (y % encode->channels[line_c].y_samples != 0) continue;

if (line_c == file_c)
{
if (encode->channels[file_c].data_type ==
EXR_PIXEL_HALF)
{
int16_t* channel_pixels = (int16_t*) (line_pixels);
for (uint32_t p = 0;
p < encode->channels[file_c].width;
p++)
{
// assert (*channel_pixels == 0);
cur_line->i32[p] = *channel_pixels++;
}
}
else
{
int32_t* channel_pixels = (int32_t*) (line_pixels);
for (uint32_t p = 0;
p < encode->channels[file_c].width;
p++)
{
// assert (*channel_pixels == 0);
cur_line->i32[p] = *channel_pixels++;
}
}

assert (next_comp == c);
cur_line = cs.exchange (cur_line, next_comp);
}

line_pixels += encode->channels[line_c].bytes_per_element *
encode->channels[line_c].width;
}
}

cur_line = cs.exchange (cur_line, next_comp);
}
}
else
{
const uint8_t* line_pixels =
static_cast<const uint8_t*> (encode->packed_buffer);

line_pixels += width * encode->channel_count;
assert (bpl * image_height == encode->packed_bytes);

for (int y = 0; y < image_height; y++)
{
for (ojph::ui32 c = 0; c < encode->channel_count; c++)
{
int file_c = cs_to_file_ch[c].file_index;

if (encode->channels[file_c].data_type == EXR_PIXEL_HALF)
{
int16_t* channel_pixels =
(int16_t*) (line_pixels + cs_to_file_ch[c].raster_line_offset);
for (uint32_t p = 0; p < encode->channels[file_c].width;
p++)
{
cur_line->i32[p] = *channel_pixels++;
//assert (cur_line->i32[p] == 0);
}
}
else
{
int32_t* channel_pixels =
(int32_t*) (line_pixels + cs_to_file_ch[c].raster_line_offset);
for (uint32_t p = 0; p < encode->channels[file_c].width;
p++)
{
cur_line->i32[p] = *channel_pixels++;
//assert (cur_line->i32[p] == 0);
}
}
assert (next_comp == c);
cur_line = cs.exchange (cur_line, next_comp);
}
line_pixels += bpl;
}
}

cs.flush ();
Expand All @@ -164,12 +347,19 @@ internal_exr_apply_ht (exr_encode_pipeline_t* encode)

int compressed_sz = static_cast<size_t> (output.tell ());

// std::ofstream outf ("out7.j2c", std::ios::binary);
// outf.write ((char*) output.get_data (), compressed_sz);
// outf.close ();

if (compressed_sz < encode->packed_bytes)
{
memcpy (encode->compressed_buffer, output.get_data (), compressed_sz);
encode->compressed_bytes = compressed_sz;
}
else { encode->compressed_bytes = encode->packed_bytes; }
else
{
encode->compressed_bytes = encode->packed_bytes;
}

return rv;
}
Loading

0 comments on commit 2a3f1c5

Please sign in to comment.