mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 21:17:44 +00:00
LibGfx: Add scaling methods to Bitmap
This commit is contained in:
parent
4233b69ecf
commit
790908ffc3
2 changed files with 111 additions and 0 deletions
|
@ -389,6 +389,115 @@ RefPtr<Gfx::Bitmap> Bitmap::flipped(Gfx::Orientation orientation) const
|
|||
return new_bitmap;
|
||||
}
|
||||
|
||||
RefPtr<Gfx::Bitmap> Bitmap::scaled(int sx, int sy) const
|
||||
{
|
||||
VERIFY(sx >= 0 && sy >= 0);
|
||||
if (sx == 1 && sy == 1)
|
||||
return this;
|
||||
|
||||
auto new_bitmap = Gfx::Bitmap::create(format(), { width() * sx, height() * sy }, scale());
|
||||
if (!new_bitmap)
|
||||
return nullptr;
|
||||
|
||||
auto old_width = physical_width();
|
||||
auto old_height = physical_height();
|
||||
|
||||
for (int y = 0; y < old_height; y++) {
|
||||
for (int x = 0; x < old_width; x++) {
|
||||
auto color = get_pixel(x, y);
|
||||
|
||||
auto base_x = x * sx;
|
||||
auto base_y = y * sy;
|
||||
for (int new_y = base_y; new_y < base_y + sy; new_y++) {
|
||||
for (int new_x = base_x; new_x < base_x + sx; new_x++) {
|
||||
new_bitmap->set_pixel(new_x, new_y, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new_bitmap;
|
||||
}
|
||||
|
||||
// http://fourier.eng.hmc.edu/e161/lectures/resize/node3.html
|
||||
RefPtr<Gfx::Bitmap> Bitmap::scaled(float sx, float sy) const
|
||||
{
|
||||
VERIFY(sx >= 0.0f && sy >= 0.0f);
|
||||
if (floorf(sx) == sx && floorf(sy) == sy)
|
||||
return scaled(static_cast<int>(sx), static_cast<int>(sy));
|
||||
|
||||
auto new_bitmap = Gfx::Bitmap::create(format(), { width() * sx, height() * sy }, scale());
|
||||
if (!new_bitmap)
|
||||
return nullptr;
|
||||
|
||||
auto old_width = physical_width();
|
||||
auto old_height = physical_height();
|
||||
auto new_width = new_bitmap->physical_width();
|
||||
auto new_height = new_bitmap->physical_height();
|
||||
|
||||
// The interpolation goes out of bounds on the bottom- and right-most edges.
|
||||
// We handle those in two specialized loops not only to make them faster, but
|
||||
// also to avoid four branch checks for every pixel.
|
||||
|
||||
for (int y = 0; y < new_height - 1; y++) {
|
||||
for (int x = 0; x < new_width - 1; x++) {
|
||||
auto p = static_cast<float>(x) * static_cast<float>(old_width - 1) / static_cast<float>(new_width - 1);
|
||||
auto q = static_cast<float>(y) * static_cast<float>(old_height - 1) / static_cast<float>(new_height - 1);
|
||||
|
||||
int i = floor(p);
|
||||
int j = floor(q);
|
||||
float u = p - static_cast<float>(i);
|
||||
float v = q - static_cast<float>(j);
|
||||
|
||||
auto a = get_pixel(i, j);
|
||||
auto b = get_pixel(i + 1, j);
|
||||
auto c = get_pixel(i, j + 1);
|
||||
auto d = get_pixel(i + 1, j + 1);
|
||||
|
||||
auto e = a.interpolate(b, u);
|
||||
auto f = c.interpolate(d, u);
|
||||
auto color = e.interpolate(f, v);
|
||||
new_bitmap->set_pixel(x, y, color);
|
||||
}
|
||||
}
|
||||
|
||||
// Bottom strip (excluding last pixel)
|
||||
auto old_bottom_y = old_height - 1;
|
||||
auto new_bottom_y = new_height - 1;
|
||||
for (int x = 0; x < new_width - 1; x++) {
|
||||
auto p = static_cast<float>(x) * static_cast<float>(old_width - 1) / static_cast<float>(new_width - 1);
|
||||
|
||||
int i = floor(p);
|
||||
float u = p - static_cast<float>(i);
|
||||
|
||||
auto a = get_pixel(i, old_bottom_y);
|
||||
auto b = get_pixel(i + 1, old_bottom_y);
|
||||
auto color = a.interpolate(b, u);
|
||||
new_bitmap->set_pixel(x, new_bottom_y, color);
|
||||
}
|
||||
|
||||
// Right strip (excluding last pixel)
|
||||
auto old_right_x = old_width - 1;
|
||||
auto new_right_x = new_width - 1;
|
||||
for (int y = 0; y < new_height - 1; y++) {
|
||||
auto q = static_cast<float>(y) * static_cast<float>(old_height - 1) / static_cast<float>(new_height - 1);
|
||||
|
||||
int j = floor(q);
|
||||
float v = q - static_cast<float>(j);
|
||||
|
||||
auto c = get_pixel(old_right_x, j);
|
||||
auto d = get_pixel(old_right_x, j + 1);
|
||||
|
||||
auto color = c.interpolate(d, v);
|
||||
new_bitmap->set_pixel(new_right_x, y, color);
|
||||
}
|
||||
|
||||
// Bottom-right pixel
|
||||
new_bitmap->set_pixel(new_width - 1, new_height - 1, get_pixel(physical_width() - 1, physical_height() - 1));
|
||||
|
||||
return new_bitmap;
|
||||
}
|
||||
|
||||
#ifdef __serenity__
|
||||
RefPtr<Bitmap> Bitmap::to_bitmap_backed_by_anon_fd() const
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue