Skip to content

Commit

Permalink
Fix some issue with image filters
Browse files Browse the repository at this point in the history
  • Loading branch information
malaterre committed Mar 1, 2022
1 parent 9d781ca commit 84dd7a5
Show file tree
Hide file tree
Showing 9 changed files with 246 additions and 16 deletions.
21 changes: 21 additions & 0 deletions doc/jplstran.md.in
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,27 @@ jplstran – lossless transformation for JPEG-LS files
**-o**, **--output**
: Specify the output file(s) to write.

**--flip** horizontal
: Mirror image horizontally (left-right).

**--flip** vertical
: Mirror image vertically (top-bottom).

**--rotate** 90
: Rotate image 90 degrees clockwise.

**--rotate** 180
: Rotate image 180 degrees.

**--rotate** 270
: Rotate image 270 degrees clockwise (or 90 ccw).

**--transpose**
: Transpose image (across UL-to-LR axis).

**--transverse**
: Transverse transpose (across UR-to-LL axis).

# COPYRIGHT

BSD-3-Clause
2 changes: 1 addition & 1 deletion factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include "image.h"

namespace jlst {
bool factory::registerFormat(const format* f, float priority)
bool factory::register_format(const format* f, float priority)
{
#if 0
auto p = std::clamp(priority, 0, 1); // c++17
Expand Down
2 changes: 1 addition & 1 deletion factory.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class factory
{
public:
static factory& instance();
bool registerFormat(const format* f, float priority = 0.5);
bool register_format(const format* f, float priority = 0.5);
format* get_format_from_type(std::string const& type) const;
format* detect_format(source& s) const;

Expand Down
149 changes: 147 additions & 2 deletions image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "utils.h"

#include <cassert>
#include <cstring> // memset
#include <stdexcept> // for invalid_argument

namespace jlst {
Expand Down Expand Up @@ -78,36 +79,180 @@ std::vector<uint8_t> image::transform(charls::interleave_mode const& interleave_

std::vector<uint8_t> image::crop(uint32_t X, uint32_t Y, uint32_t width, uint32_t height)
{
assert(get_image_data().stride() == 0);
auto& frame_info = get_image_info().frame_info();
auto& inbuffer = get_image_data().pixel_data();
std::vector<uint8_t> out;
size_t nbytes = frame_info.component_count * ((frame_info.bits_per_sample + 7) / 8);
out.resize(width * height * nbytes);
auto inwidth = frame_info.width;
for (uint32_t y{}; y != frame_info.height; ++y)
{
for (uint32_t x{}; x != frame_info.width; ++x)
{
if ((x >= X && x < X + width) && (y >= Y && y < Y + height))
{
std::memcpy(&out[(y - Y) * width * nbytes + (x - X) * nbytes], &inbuffer[y * inwidth * nbytes + x * nbytes],
nbytes);
}
}
}
return out;
}
std::vector<uint8_t> image::flip(bool vertical)
{
assert(get_image_data().stride() == 0);
auto& frame_info = get_image_info().frame_info();
auto& inbuffer = get_image_data().pixel_data();
std::vector<uint8_t> out;
out.resize(inbuffer.size());
size_t nbytes = frame_info.component_count * ((frame_info.bits_per_sample + 7) / 8);
auto inheigth = frame_info.height;
auto inwidth = frame_info.width;
if (vertical)
{
for (uint32_t y{}; y != frame_info.height; ++y)
{
std::memcpy(&out[y * inwidth * nbytes], &inbuffer[(inheigth - y - 1) * inwidth * nbytes], nbytes * inwidth);
}
}
else
{
// horizontal
for (uint32_t y{}; y != frame_info.height; ++y)
{
for (uint32_t x{}; x != frame_info.width; ++x)
{
std::memcpy(&out[y * inwidth * nbytes + x * nbytes],
&inbuffer[y * inwidth * nbytes + (inwidth - x - 1) * nbytes], nbytes);
}
}
}
return out;
}
std::vector<uint8_t> image::rotate(int degree)
{
assert(degree == 90 || degree == 180 || degree == 270);
assert(get_image_data().stride() == 0);
auto& frame_info = get_image_info().frame_info();
auto& inbuffer = get_image_data().pixel_data();
std::vector<uint8_t> out;
out.resize(inbuffer.size());
size_t nbytes = frame_info.component_count * ((frame_info.bits_per_sample + 7) / 8);
if (degree == 90)
{
auto oldheight = frame_info.height;
auto oldwidth = frame_info.width;
auto newheight = frame_info.width;
auto newwidth = frame_info.height;

for (uint32_t y{}; y != newheight; ++y)
{
for (uint32_t x{}; x != newwidth; ++x)
{
std::memcpy(&out[y * newwidth * nbytes + x * nbytes],
&inbuffer[(oldheight - x - 1) * oldwidth * nbytes + y * nbytes], nbytes);
}
}
}
else if (degree == 180)
{
auto oldheight = frame_info.height;
auto oldwidth = frame_info.width;
for (uint32_t y{}; y != oldheight; ++y)
{
for (uint32_t x{}; x != oldwidth; ++x)
{
std::memcpy(&out[y * oldwidth * nbytes + x * nbytes],
&inbuffer[(oldheight - y - 1) * oldwidth * nbytes + (oldwidth - x - 1) * nbytes], nbytes);
}
}
}
else if (degree == 270)
{
auto oldheight = frame_info.height;
auto oldwidth = frame_info.width;
auto newheight = frame_info.width;
auto newwidth = frame_info.height;

for (uint32_t y{}; y != newheight; ++y)
{
for (uint32_t x{}; x != newwidth; ++x)
{
std::memcpy(&out[y * newwidth * nbytes + x * nbytes],
&inbuffer[x * oldwidth * nbytes + (oldwidth - y - 1) * nbytes], nbytes);
}
}
}
return out;
}
std::vector<uint8_t> image::transpose()
{
assert(get_image_data().stride() == 0);
auto& frame_info = get_image_info().frame_info();
auto& inbuffer = get_image_data().pixel_data();
std::vector<uint8_t> out;
out.resize(inbuffer.size());
size_t nbytes = frame_info.component_count * ((frame_info.bits_per_sample + 7) / 8);

auto oldheight = frame_info.height;
auto oldwidth = frame_info.width;
auto newheight = frame_info.width;
auto newwidth = frame_info.height;

for (uint32_t y{}; y != newheight; ++y)
{
for (uint32_t x{}; x != newwidth; ++x)
{
std::memcpy(&out[y * newwidth * nbytes + x * nbytes], &inbuffer[x * oldwidth * nbytes + y * nbytes], nbytes);
}
}
return out;
}
std::vector<uint8_t> image::transverse()
{
assert(get_image_data().stride() == 0);
auto& frame_info = get_image_info().frame_info();
auto& inbuffer = get_image_data().pixel_data();
std::vector<uint8_t> out;
out.resize(inbuffer.size());
size_t nbytes = frame_info.component_count * ((frame_info.bits_per_sample + 7) / 8);

auto oldheight = frame_info.height;
auto oldwidth = frame_info.width;
auto newheight = frame_info.width;
auto newwidth = frame_info.height;

for (uint32_t y{}; y != newheight; ++y)
{
for (uint32_t x{}; x != newwidth; ++x)
{
std::memcpy(&out[y * newwidth * nbytes + x * nbytes],
&inbuffer[(oldheight - x - 1) * oldwidth * nbytes + (oldwidth - y - 1) * nbytes], nbytes);
}
}
return out;
}
std::vector<uint8_t> image::wipe(uint32_t X, uint32_t Y, uint32_t width, uint32_t height)
{
assert(get_image_data().stride() == 0);
auto& frame_info = get_image_info().frame_info();
auto& inbuffer = get_image_data().pixel_data();
std::vector<uint8_t> out;
out.resize(inbuffer.size());
size_t nbytes = frame_info.component_count * ((frame_info.bits_per_sample + 7) / 8);
auto inwidth = frame_info.width;
for (uint32_t y{}; y != frame_info.height; ++y)
{
for (uint32_t x{}; x != frame_info.width; ++x)
{
if ((x >= X && x < X + width) && (y >= Y && y < Y + height))
{
out[y * width + x] = 0;
std::memset(&out[y * inwidth * nbytes + x * nbytes], 0, nbytes);
}
else
{
out[y * width + x] = inbuffer[y + width + x];
std::memcpy(&out[y * inwidth * nbytes + x * nbytes], &inbuffer[y * inwidth * nbytes + x * nbytes], nbytes);
}
}
}
Expand Down
58 changes: 50 additions & 8 deletions jls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,14 +179,17 @@ static void patch_header(std::vector<uint8_t>& v, int near)
++it;
if (it != v.end() && *it == 0xda)
{
++it;
pos = it - v.begin();
}
}
}
if (pos != 0)
{
v[pos + 6] = near;
}
if (pos == 0)
throw std::runtime_error("cannot find scan header");
// Ls:
uint16_t ls = v[pos + 0] << 8 | v[pos + 1];

v[pos + 9] = near;
}
} // end namespace

Expand All @@ -204,18 +207,57 @@ void jls::transform(dest& d, source& s, const tran_options& to) const
jo.standard_spiff_header = decoder.spiff_header_has_value();

jlst::image output_image;
if (to.type == tran_options::transform_type::wipe)
if (to.type == tran_options::transform_type::crop)
{
output_image.get_image_info() = input_image.get_image_info();
auto& region = to.region;
output_image.get_image_info().frame_info().width = region.Width;
output_image.get_image_info().frame_info().height = region.Height;
output_image.get_image_data().pixel_data() = input_image.crop(region.X, region.Y, region.Width, region.Height);
}
else if (to.type == tran_options::transform_type::flip)
{
output_image.get_image_info() = input_image.get_image_info();
output_image.get_image_data().pixel_data() = input_image.flip(to.vertical);
}
else if (to.type == tran_options::transform_type::rotate)
{
output_image.get_image_info() = input_image.get_image_info();
if (to.degree == 90 || to.degree == 270)
{
output_image.get_image_info().frame_info().width = input_image.get_image_info().frame_info().height;
output_image.get_image_info().frame_info().height = input_image.get_image_info().frame_info().width;
}
output_image.get_image_data().pixel_data() = input_image.rotate(to.degree);
}
else if (to.type == tran_options::transform_type::transpose)
{
output_image.get_image_info() = input_image.get_image_info();
output_image.get_image_info().frame_info().width = input_image.get_image_info().frame_info().height;
output_image.get_image_info().frame_info().height = input_image.get_image_info().frame_info().width;

output_image.get_image_data().pixel_data() = input_image.transpose();
}
else if (to.type == tran_options::transform_type::transverse)
{
output_image.get_image_info() = input_image.get_image_info();
output_image.get_image_info().frame_info().width = input_image.get_image_info().frame_info().height;
output_image.get_image_info().frame_info().height = input_image.get_image_info().frame_info().width;

output_image.get_image_data().pixel_data() = input_image.transverse();
}
else if (to.type == tran_options::transform_type::wipe)
{
output_image.get_image_info() = input_image.get_image_info();
auto& region = to.region;
output_image.get_image_data().pixel_data() = input_image.wipe(region.X, region.Y, region.Width, region.Height);
}
else
{
throw std::runtime_error("todo");
throw std::runtime_error("wotsit");
}
auto encoded_buffer{compress(output_image, jo)};
patch_header(encoded_buffer, decoder.near_lossless());
// patch_header(encoded_buffer, decoder.near_lossless());
d.write(encoded_buffer.data(), encoded_buffer.size());
}

Expand All @@ -229,5 +271,5 @@ static const format* get()
static const jls jls_;
return &jls_;
}
static bool b = factory::instance().registerFormat(get(), 1);
static bool b = factory::instance().register_format(get(), 1);
} // namespace jlst
25 changes: 23 additions & 2 deletions jplstran_options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,33 @@ bool tran_options::process(int argc, char* argv[])
if (vm.count("crop"))
{
type = transform_type::crop;
region.Width = region_tuple.values[0];
region.Height = region_tuple.values[1];
region.X = region_tuple.values[2];
region.Y = region_tuple.values[3];
}
else if (vm.count("flip"))
type = transform_type::rotate;
{
type = transform_type::flip;
if (flip == "vertical")
{
vertical = true;
}
else if (flip == "horizontal")
{
vertical = false;
}
else
{
throw std::runtime_error("flip:" + flip);
}
}
else if (vm.count("rotate"))
{
type = transform_type::rotate;
if (degree != 90 && degree != 180 && degree != 270)
throw std::runtime_error("rotate:" + degree);
}
else if (vm.count("transpose"))
type = transform_type::transpose;
else if (vm.count("transverse"))
Expand All @@ -105,7 +127,6 @@ bool tran_options::process(int argc, char* argv[])
region.X = region_tuple.values[2];
region.Y = region_tuple.values[3];
}

} // namespace boost::program_options;
return true;
}
Expand Down
1 change: 1 addition & 0 deletions jplstran_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ struct tran_options final : options
};
transform_type type{};
int degree{};
bool vertical{};
struct
{
uint32_t X;
Expand Down
2 changes: 1 addition & 1 deletion pnm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -189,5 +189,5 @@ static const format* get()
return &pnm_;
}

static bool b = factory::instance().registerFormat(get());
static bool b = factory::instance().register_format(get());
} // namespace jlst
2 changes: 1 addition & 1 deletion raw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,5 +112,5 @@ static const format* get()
return &raw_;
}
// set priority to 0 so that `raw` is always tested last
static bool b = factory::instance().registerFormat(get(), 0);
static bool b = factory::instance().register_format(get(), 0);
} // namespace jlst

0 comments on commit 84dd7a5

Please sign in to comment.