BuildSystem: Move all userpace libraries under the userspace directory
As the number of libraries is increasing, root directory starts to expand. This adds better organization for libraries
This commit is contained in:
200
userspace/libraries/LibImage/Image.cpp
Normal file
200
userspace/libraries/LibImage/Image.cpp
Normal file
@@ -0,0 +1,200 @@
|
||||
#include <BAN/ScopeGuard.h>
|
||||
#include <BAN/String.h>
|
||||
|
||||
#include <LibImage/Image.h>
|
||||
#include <LibImage/Netbpm.h>
|
||||
#include <LibImage/PNG.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
namespace LibImage
|
||||
{
|
||||
|
||||
BAN::ErrorOr<BAN::UniqPtr<Image>> Image::load_from_file(BAN::StringView path)
|
||||
{
|
||||
int fd = -1;
|
||||
|
||||
if (path.data()[path.size()] == '\0')
|
||||
{
|
||||
fd = open(path.data(), O_RDONLY);
|
||||
}
|
||||
else
|
||||
{
|
||||
BAN::String path_str;
|
||||
TRY(path_str.append(path));
|
||||
fd = open(path_str.data(), O_RDONLY);
|
||||
}
|
||||
|
||||
if (fd == -1)
|
||||
{
|
||||
fprintf(stddbg, "open: %s\n", strerror(errno));
|
||||
return BAN::Error::from_errno(errno);
|
||||
}
|
||||
|
||||
BAN::ScopeGuard guard_file_close([fd] { close(fd); });
|
||||
|
||||
struct stat st;
|
||||
if (fstat(fd, &st) == -1)
|
||||
{
|
||||
fprintf(stddbg, "fstat: %s\n", strerror(errno));
|
||||
return BAN::Error::from_errno(errno);
|
||||
}
|
||||
|
||||
void* addr = mmap(nullptr, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
if (addr == MAP_FAILED)
|
||||
{
|
||||
fprintf(stddbg, "mmap: %s\n", strerror(errno));
|
||||
return BAN::Error::from_errno(errno);
|
||||
}
|
||||
|
||||
BAN::ScopeGuard guard_munmap([&] { munmap(addr, st.st_size); });
|
||||
|
||||
auto image_data_span = BAN::ConstByteSpan(reinterpret_cast<uint8_t*>(addr), st.st_size);
|
||||
|
||||
if (probe_netbpm(image_data_span))
|
||||
return TRY(load_netbpm(image_data_span));
|
||||
|
||||
if (probe_png(image_data_span))
|
||||
return TRY(load_png(image_data_span));
|
||||
|
||||
fprintf(stderr, "unrecognized image format\n");
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
}
|
||||
|
||||
|
||||
struct FloatingColor
|
||||
{
|
||||
double r, g, b, a;
|
||||
|
||||
constexpr FloatingColor() {}
|
||||
constexpr FloatingColor(double r, double g, double b, double a)
|
||||
: r(r), g(g), b(b), a(a)
|
||||
{}
|
||||
constexpr FloatingColor(Image::Color c)
|
||||
: r(c.r), g(c.g), b(c.b), a(c.a)
|
||||
{}
|
||||
constexpr FloatingColor operator*(double value) const
|
||||
{
|
||||
return FloatingColor(r * value, g * value, b * value, a * value);
|
||||
}
|
||||
constexpr FloatingColor operator+(FloatingColor other) const
|
||||
{
|
||||
return FloatingColor(r + other.r, g + other.g, b + other.b, a + other.a);
|
||||
}
|
||||
constexpr Image::Color as_color() const
|
||||
{
|
||||
return Image::Color {
|
||||
.r = static_cast<uint8_t>(BAN::Math::clamp<double>(r, 0.0, 255.0)),
|
||||
.g = static_cast<uint8_t>(BAN::Math::clamp<double>(g, 0.0, 255.0)),
|
||||
.b = static_cast<uint8_t>(BAN::Math::clamp<double>(b, 0.0, 255.0)),
|
||||
.a = static_cast<uint8_t>(BAN::Math::clamp<double>(a, 0.0, 255.0)),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
BAN::ErrorOr<BAN::UniqPtr<Image>> Image::resize(uint64_t new_width, uint64_t new_height, ResizeAlgorithm algorithm)
|
||||
{
|
||||
if (!validate_size(new_width, new_height))
|
||||
return BAN::Error::from_errno(EOVERFLOW);
|
||||
|
||||
const double ratio_x = (double)width() / new_width;
|
||||
const double ratio_y = (double)height() / new_height;
|
||||
|
||||
const auto get_clamped_color =
|
||||
[this](int64_t x, int64_t y)
|
||||
{
|
||||
x = BAN::Math::clamp<int64_t>(x, 0, width() - 1);
|
||||
y = BAN::Math::clamp<int64_t>(y, 0, height() - 1);
|
||||
return get_color(x, y);
|
||||
};
|
||||
|
||||
switch (algorithm)
|
||||
{
|
||||
case ResizeAlgorithm::Nearest:
|
||||
{
|
||||
BAN::Vector<Color> nearest_bitmap;
|
||||
TRY(nearest_bitmap.resize(new_width * new_height));
|
||||
for (uint64_t y = 0; y < new_height; y++)
|
||||
for (uint64_t x = 0; x < new_width; x++)
|
||||
nearest_bitmap[y * new_width + x] = get_clamped_color(x * ratio_x, y * ratio_y);
|
||||
return TRY(BAN::UniqPtr<Image>::create(new_width, new_height, BAN::move(nearest_bitmap)));
|
||||
}
|
||||
case ResizeAlgorithm::Linear:
|
||||
{
|
||||
BAN::Vector<Color> bilinear_bitmap;
|
||||
TRY(bilinear_bitmap.resize(new_width * new_height));
|
||||
|
||||
for (uint64_t y = 0; y < new_height; y++)
|
||||
{
|
||||
for (uint64_t x = 0; x < new_width; x++)
|
||||
{
|
||||
const double src_x = x * ratio_x;
|
||||
const double src_y = y * ratio_y;
|
||||
const double weight_x = src_x - floor(src_x);
|
||||
const double weight_y = src_y - floor(src_y);
|
||||
|
||||
const Color avg_t = Color::average(
|
||||
get_clamped_color(src_x + 0.0, src_y),
|
||||
get_clamped_color(src_x + 1.0, src_y),
|
||||
weight_x
|
||||
);
|
||||
const Color avg_b = Color::average(
|
||||
get_clamped_color(src_x + 0.0, src_y + 1.0),
|
||||
get_clamped_color(src_x + 0.0, src_y + 1.0),
|
||||
weight_x
|
||||
);
|
||||
bilinear_bitmap[y * new_width + x] = Color::average(avg_t, avg_b, weight_y);
|
||||
}
|
||||
}
|
||||
|
||||
return TRY(BAN::UniqPtr<Image>::create(new_width, new_height, BAN::move(bilinear_bitmap)));
|
||||
}
|
||||
case ResizeAlgorithm::Cubic:
|
||||
{
|
||||
BAN::Vector<Color> bicubic_bitmap;
|
||||
TRY(bicubic_bitmap.resize(new_width * new_height));
|
||||
|
||||
constexpr auto cubic_interpolate =
|
||||
[](FloatingColor p[4], double x)
|
||||
{
|
||||
const auto a = (p[0] * -0.5) + (p[1] * 1.5) + (p[2] * -1.5) + (p[3] * 0.5);
|
||||
const auto b = p[0] + (p[1] * -2.5) + (p[2] * 2.0) + (p[3] * -0.5);
|
||||
const auto c = (p[0] * -0.5) + (p[2] * 0.5);
|
||||
const auto d = p[1];
|
||||
return (a * x * x * x) + (b * x * x) + (c * x) + d;
|
||||
};
|
||||
|
||||
for (uint64_t y = 0; y < new_height; y++)
|
||||
{
|
||||
for (uint64_t x = 0; x < new_width; x++)
|
||||
{
|
||||
const double src_x = x * ratio_x;
|
||||
const double src_y = y * ratio_y;
|
||||
const double weight_x = src_x - floor(src_x);
|
||||
const double weight_y = src_y - floor(src_y);
|
||||
|
||||
FloatingColor values[4];
|
||||
for (int64_t m = -1; m <= 2; m++)
|
||||
{
|
||||
FloatingColor p[4];
|
||||
p[0] = get_clamped_color(src_x - 1.0, src_y + m);
|
||||
p[1] = get_clamped_color(src_x + 0.0, src_y + m);
|
||||
p[2] = get_clamped_color(src_x + 1.0, src_y + m);
|
||||
p[3] = get_clamped_color(src_x + 2.0, src_y + m);
|
||||
values[m + 1] = cubic_interpolate(p, weight_x);
|
||||
}
|
||||
|
||||
bicubic_bitmap[y * new_width + x] = cubic_interpolate(values, weight_y).as_color();
|
||||
}
|
||||
}
|
||||
|
||||
return TRY(BAN::UniqPtr<Image>::create(new_width, new_height, BAN::move(bicubic_bitmap)));
|
||||
}
|
||||
}
|
||||
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user