Kaynağa Gözat

Implement `rotate_90/rotate_180` functions to `Image`

Yuri Rubinsky 3 yıl önce
ebeveyn
işleme
7e66903d56
3 değiştirilmiş dosya ile 121 ekleme ve 0 silme
  1. 105 0
      core/io/image.cpp
  2. 3 0
      core/io/image.h
  3. 13 0
      doc/classes/Image.xml

+ 105 - 0
core/io/image.cpp

@@ -1339,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.");
 
@@ -3217,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);

+ 3 - 0
core/io/image.h

@@ -254,6 +254,9 @@ public:
 	void crop_from_point(int p_x, int p_y, int p_width, int p_height);
 	void crop(int p_width, int p_height);
 
+	void rotate_90(ClockDirection p_direction);
+	void rotate_180();
+
 	void flip_x();
 	void flip_y();
 

+ 13 - 0
doc/classes/Image.xml

@@ -378,6 +378,19 @@
 				Converts a standard RGBE (Red Green Blue Exponent) image to an sRGB image.
 			</description>
 		</method>
+		<method name="rotate_180">
+			<return type="void" />
+			<description>
+				Rotates the image by [code]180[/code] degrees. The width and height of the image must be greater than [code]1[/code].
+			</description>
+		</method>
+		<method name="rotate_90">
+			<return type="void" />
+			<argument index="0" name="direction" type="int" enum="ClockDirection" />
+			<description>
+				Rotates the image in the specified [code]direction[/code] by [code]90[/code] degrees. The width and height of the image must be greater than [code]1[/code]. If the width and height are not equal, the image will be resized.
+			</description>
+		</method>
 		<method name="save_exr" qualifiers="const">
 			<return type="int" enum="Error" />
 			<argument index="0" name="path" type="String" />