diff options
Diffstat (limited to 'core/io/image.cpp')
-rw-r--r-- | core/io/image.cpp | 154 |
1 files changed, 142 insertions, 12 deletions
diff --git a/core/io/image.cpp b/core/io/image.cpp index a945d3e6cd..0f20aabd7e 100644 --- a/core/io/image.cpp +++ b/core/io/image.cpp @@ -85,6 +85,7 @@ SaveJPGFunc Image::save_jpg_func = nullptr; SaveEXRFunc Image::save_exr_func = nullptr; SavePNGBufferFunc Image::save_png_buffer_func = nullptr; +SaveEXRBufferFunc Image::save_exr_buffer_func = nullptr; SaveJPGBufferFunc Image::save_jpg_buffer_func = nullptr; SaveWebPFunc Image::save_webp_func = nullptr; @@ -1338,6 +1339,108 @@ void Image::crop(int p_width, int p_height) { crop_from_point(0, 0, p_width, p_height); } +void Image::rotate_90(ClockDirection p_direction) { + ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot rotate in compressed or custom image formats."); + ERR_FAIL_COND_MSG(width <= 1, "The Image width specified (" + itos(width) + " pixels) must be greater than 1 pixels."); + ERR_FAIL_COND_MSG(height <= 1, "The Image height specified (" + itos(height) + " pixels) must be greater than 1 pixels."); + + int saved_width = height; + int saved_height = width; + + if (width != height) { + int n = MAX(width, height); + resize(n, n, INTERPOLATE_NEAREST); + } + + bool used_mipmaps = has_mipmaps(); + if (used_mipmaps) { + clear_mipmaps(); + } + + { + uint8_t *w = data.ptrw(); + uint8_t src[16]; + uint8_t dst[16]; + uint32_t pixel_size = get_format_pixel_size(format); + + // Flip. + + if (p_direction == CLOCKWISE) { + for (int y = 0; y < height / 2; y++) { + for (int x = 0; x < width; x++) { + _get_pixelb(x, y, pixel_size, w, src); + _get_pixelb(x, height - y - 1, pixel_size, w, dst); + + _put_pixelb(x, height - y - 1, pixel_size, w, src); + _put_pixelb(x, y, pixel_size, w, dst); + } + } + } else { + for (int y = 0; y < height; y++) { + for (int x = 0; x < width / 2; x++) { + _get_pixelb(x, y, pixel_size, w, src); + _get_pixelb(width - x - 1, y, pixel_size, w, dst); + + _put_pixelb(width - x - 1, y, pixel_size, w, src); + _put_pixelb(x, y, pixel_size, w, dst); + } + } + } + + // Transpose. + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + if (x < y) { + _get_pixelb(x, y, pixel_size, w, src); + _get_pixelb(y, x, pixel_size, w, dst); + + _put_pixelb(y, x, pixel_size, w, src); + _put_pixelb(x, y, pixel_size, w, dst); + } + } + } + } + + if (saved_width != saved_height) { + resize(saved_width, saved_height, INTERPOLATE_NEAREST); + } else if (used_mipmaps) { + generate_mipmaps(); + } +} + +void Image::rotate_180() { + ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot rotate in compressed or custom image formats."); + ERR_FAIL_COND_MSG(width <= 1, "The Image width specified (" + itos(width) + " pixels) must be greater than 1 pixels."); + ERR_FAIL_COND_MSG(height <= 1, "The Image height specified (" + itos(height) + " pixels) must be greater than 1 pixels."); + + bool used_mipmaps = has_mipmaps(); + if (used_mipmaps) { + clear_mipmaps(); + } + + { + uint8_t *w = data.ptrw(); + uint8_t src[16]; + uint8_t dst[16]; + uint32_t pixel_size = get_format_pixel_size(format); + + for (int y = 0; y < height / 2; y++) { + for (int x = 0; x < width; x++) { + _get_pixelb(x, y, pixel_size, w, src); + _get_pixelb(width - x - 1, height - y - 1, pixel_size, w, dst); + + _put_pixelb(width - x - 1, height - y - 1, pixel_size, w, src); + _put_pixelb(x, y, pixel_size, w, dst); + } + } + } + + if (used_mipmaps) { + generate_mipmaps(); + } +} + void Image::flip_y() { ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot flip_y in compressed or custom image formats."); @@ -2283,6 +2386,21 @@ Error Image::load(const String &p_path) { return ImageLoader::load_image(p_path, this); } +Ref<Image> Image::load_from_file(const String &p_path) { +#ifdef DEBUG_ENABLED + if (p_path.begins_with("res://") && ResourceLoader::exists(p_path)) { + WARN_PRINT("Loaded resource as image file, this will not work on export: '" + p_path + "'. Instead, import the image file as an Image resource and load it normally as a resource."); + } +#endif + Ref<Image> image; + image.instantiate(); + Error err = ImageLoader::load_image(p_path, image); + if (err != OK) { + ERR_FAIL_V_MSG(Ref<Image>(), vformat("Failed to load image. Error %d", err)); + } + return image; +} + Error Image::save_png(const String &p_path) const { if (save_png_func == nullptr) { return ERR_UNAVAILABLE; @@ -2323,6 +2441,13 @@ Error Image::save_exr(const String &p_path, bool p_grayscale) const { return save_exr_func(p_path, Ref<Image>((Image *)this), p_grayscale); } +Vector<uint8_t> Image::save_exr_to_buffer(bool p_grayscale) const { + if (save_exr_buffer_func == nullptr) { + return Vector<uint8_t>(); + } + return save_exr_buffer_func(Ref<Image>((Image *)this), p_grayscale); +} + Error Image::save_webp(const String &p_path, const bool p_lossy, const float p_quality) const { if (save_webp_func == nullptr) { return ERR_UNAVAILABLE; @@ -2455,15 +2580,15 @@ Image::Image(int p_width, int p_height, bool p_mipmaps, Format p_format, const V create(p_width, p_height, p_mipmaps, p_format, p_data); } -Rect2 Image::get_used_rect() const { +Rect2i Image::get_used_rect() const { if (format != FORMAT_LA8 && format != FORMAT_RGBA8 && format != FORMAT_RGBAF && format != FORMAT_RGBAH && format != FORMAT_RGBA4444 && format != FORMAT_RGB565) { - return Rect2(Point2(), Size2(width, height)); + return Rect2i(0, 0, width, height); } int len = data.size(); if (len == 0) { - return Rect2(); + return Rect2i(); } int minx = 0xFFFFFF, miny = 0xFFFFFFF; @@ -2489,15 +2614,15 @@ Rect2 Image::get_used_rect() const { } if (maxx == -1) { - return Rect2(); + return Rect2i(); } else { - return Rect2(minx, miny, maxx - minx + 1, maxy - miny + 1); + return Rect2i(minx, miny, maxx - minx + 1, maxy - miny + 1); } } -Ref<Image> Image::get_rect(const Rect2 &p_area) const { +Ref<Image> Image::get_rect(const Rect2i &p_area) const { Ref<Image> img = memnew(Image(p_area.size.x, p_area.size.y, mipmaps, format)); - img->blit_rect(Ref<Image>((Image *)this), p_area, Point2(0, 0)); + img->blit_rect(Ref<Image>((Image *)this), p_area, Point2i(0, 0)); return img; } @@ -2534,7 +2659,7 @@ void Image::_get_clipped_src_and_dest_rects(const Ref<Image> &p_src, const Rect2 r_clipped_dest_rect.size.y = r_clipped_src_rect.size.y; } -void Image::blit_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const Point2 &p_dest) { +void Image::blit_rect(const Ref<Image> &p_src, const Rect2i &p_src_rect, const Point2i &p_dest) { ERR_FAIL_COND_MSG(p_src.is_null(), "It's not a reference to a valid Image object."); int dsize = data.size(); int srcdsize = p_src->data.size(); @@ -2576,7 +2701,7 @@ void Image::blit_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const Po } } -void Image::blit_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, const Rect2 &p_src_rect, const Point2 &p_dest) { +void Image::blit_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, const Rect2i &p_src_rect, const Point2i &p_dest) { ERR_FAIL_COND_MSG(p_src.is_null(), "It's not a reference to a valid Image object."); ERR_FAIL_COND_MSG(p_mask.is_null(), "It's not a reference to a valid Image object."); int dsize = data.size(); @@ -2626,7 +2751,7 @@ void Image::blit_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, co } } -void Image::blend_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const Point2 &p_dest) { +void Image::blend_rect(const Ref<Image> &p_src, const Rect2i &p_src_rect, const Point2i &p_dest) { ERR_FAIL_COND_MSG(p_src.is_null(), "It's not a reference to a valid Image object."); int dsize = data.size(); int srcdsize = p_src->data.size(); @@ -2661,7 +2786,7 @@ void Image::blend_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const P } } -void Image::blend_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, const Rect2 &p_src_rect, const Point2 &p_dest) { +void Image::blend_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, const Rect2i &p_src_rect, const Point2i &p_dest) { ERR_FAIL_COND_MSG(p_src.is_null(), "It's not a reference to a valid Image object."); ERR_FAIL_COND_MSG(p_mask.is_null(), "It's not a reference to a valid Image object."); int dsize = data.size(); @@ -2733,7 +2858,7 @@ void Image::fill(const Color &p_color) { _repeat_pixel_over_subsequent_memory(dst_data_ptr, pixel_size, width * height); } -void Image::fill_rect(const Rect2 &p_rect, const Color &p_color) { +void Image::fill_rect(const Rect2i &p_rect, const Color &p_color) { ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot fill rect in compressed or custom image formats."); Rect2i r = Rect2i(0, 0, width, height).intersection(p_rect.abs()); @@ -3175,11 +3300,13 @@ void Image::_bind_methods() { ClassDB::bind_method(D_METHOD("is_empty"), &Image::is_empty); ClassDB::bind_method(D_METHOD("load", "path"), &Image::load); + ClassDB::bind_static_method("Image", D_METHOD("load_from_file", "path"), &Image::load_from_file); ClassDB::bind_method(D_METHOD("save_png", "path"), &Image::save_png); ClassDB::bind_method(D_METHOD("save_png_to_buffer"), &Image::save_png_to_buffer); ClassDB::bind_method(D_METHOD("save_jpg", "path", "quality"), &Image::save_jpg, DEFVAL(0.75)); ClassDB::bind_method(D_METHOD("save_jpg_to_buffer", "quality"), &Image::save_jpg_to_buffer, DEFVAL(0.75)); ClassDB::bind_method(D_METHOD("save_exr", "path", "grayscale"), &Image::save_exr, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("save_exr_to_buffer", "grayscale"), &Image::save_exr_to_buffer, DEFVAL(false)); ClassDB::bind_method(D_METHOD("save_webp", "path", "lossy", "quality"), &Image::save_webp, DEFVAL(false), DEFVAL(0.75f)); ClassDB::bind_method(D_METHOD("save_webp_to_buffer", "lossy", "quality"), &Image::save_webp_to_buffer, DEFVAL(false), DEFVAL(0.75f)); @@ -3192,6 +3319,9 @@ void Image::_bind_methods() { ClassDB::bind_method(D_METHOD("decompress"), &Image::decompress); ClassDB::bind_method(D_METHOD("is_compressed"), &Image::is_compressed); + ClassDB::bind_method(D_METHOD("rotate_90", "direction"), &Image::rotate_90); + ClassDB::bind_method(D_METHOD("rotate_180"), &Image::rotate_180); + ClassDB::bind_method(D_METHOD("fix_alpha_edges"), &Image::fix_alpha_edges); ClassDB::bind_method(D_METHOD("premultiply_alpha"), &Image::premultiply_alpha); ClassDB::bind_method(D_METHOD("srgb_to_linear"), &Image::srgb_to_linear); |