|
@@ -192,166 +192,6 @@ void Bitmap::apply_mask(Gfx::Bitmap const& mask, MaskKind mask_kind)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-ErrorOr<NonnullRefPtr<Gfx::Bitmap>> Bitmap::scaled(int sx, int sy) const
|
|
|
-{
|
|
|
- VERIFY(sx >= 0 && sy >= 0);
|
|
|
- if (sx == 1 && sy == 1)
|
|
|
- return clone();
|
|
|
-
|
|
|
- auto new_bitmap = TRY(Gfx::Bitmap::create(format(), alpha_type(), { width() * sx, height() * sy }));
|
|
|
-
|
|
|
- auto old_width = width();
|
|
|
- auto old_height = 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;
|
|
|
-}
|
|
|
-
|
|
|
-ErrorOr<NonnullRefPtr<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));
|
|
|
-
|
|
|
- int scaled_width = (int)ceilf(sx * (float)width());
|
|
|
- int scaled_height = (int)ceilf(sy * (float)height());
|
|
|
- return scaled_to_size({ scaled_width, scaled_height });
|
|
|
-}
|
|
|
-
|
|
|
-// http://fourier.eng.hmc.edu/e161/lectures/resize/node3.html
|
|
|
-ErrorOr<NonnullRefPtr<Gfx::Bitmap>> Bitmap::scaled_to_size(Gfx::IntSize size) const
|
|
|
-{
|
|
|
- auto new_bitmap = TRY(Gfx::Bitmap::create(format(), alpha_type(), size));
|
|
|
-
|
|
|
- auto old_width = width();
|
|
|
- auto old_height = height();
|
|
|
- auto new_width = new_bitmap->width();
|
|
|
- auto new_height = new_bitmap->height();
|
|
|
-
|
|
|
- if (old_width == 1 && old_height == 1) {
|
|
|
- new_bitmap->fill(get_pixel(0, 0));
|
|
|
- return new_bitmap;
|
|
|
- }
|
|
|
-
|
|
|
- if (old_width > 1 && old_height > 1) {
|
|
|
- // 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 = floorf(p);
|
|
|
- int j = floorf(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.mixed_with(b, u);
|
|
|
- auto f = c.mixed_with(d, u);
|
|
|
- auto color = e.mixed_with(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 = floorf(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.mixed_with(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 = floorf(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.mixed_with(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(width() - 1, height() - 1));
|
|
|
- return new_bitmap;
|
|
|
- } else if (old_height == 1) {
|
|
|
- // Copy horizontal strip multiple times (excluding last pixel to out of bounds).
|
|
|
- auto old_bottom_y = old_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 = floorf(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.mixed_with(b, u);
|
|
|
- for (int new_bottom_y = 0; new_bottom_y < new_height; new_bottom_y++) {
|
|
|
- // Interpolate color only once and then copy into all columns.
|
|
|
- new_bitmap->set_pixel(x, new_bottom_y, color);
|
|
|
- }
|
|
|
- }
|
|
|
- for (int new_bottom_y = 0; new_bottom_y < new_height; new_bottom_y++) {
|
|
|
- // Copy last pixel of horizontal strip
|
|
|
- new_bitmap->set_pixel(new_width - 1, new_bottom_y, get_pixel(width() - 1, old_bottom_y));
|
|
|
- }
|
|
|
- return new_bitmap;
|
|
|
- } else if (old_width == 1) {
|
|
|
- // Copy vertical strip multiple times (excluding last pixel to avoid out of bounds).
|
|
|
- auto old_right_x = old_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 = floorf(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.mixed_with(d, v);
|
|
|
- for (int new_right_x = 0; new_right_x < new_width; new_right_x++) {
|
|
|
- // Interpolate color only once and copy into all rows.
|
|
|
- new_bitmap->set_pixel(new_right_x, y, color);
|
|
|
- }
|
|
|
- }
|
|
|
- for (int new_right_x = 0; new_right_x < new_width; new_right_x++) {
|
|
|
- // Copy last pixel of vertical strip
|
|
|
- new_bitmap->set_pixel(new_right_x, new_height - 1, get_pixel(old_right_x, height() - 1));
|
|
|
- }
|
|
|
- }
|
|
|
- return new_bitmap;
|
|
|
-}
|
|
|
-
|
|
|
ErrorOr<NonnullRefPtr<Gfx::Bitmap>> Bitmap::cropped(Gfx::IntRect crop, Optional<BitmapFormat> new_bitmap_format) const
|
|
|
{
|
|
|
auto new_bitmap = TRY(Gfx::Bitmap::create(new_bitmap_format.value_or(format()), alpha_type(), { crop.width(), crop.height() }));
|