Godot中节点使用的图片是Texture2D
或其子类型,而涉及图片处理,大多数功能在Image
类型中,并且我们通常需要频繁的构造Image
和ImageTexture
类型。
为了封装构造Image
和ImageTexture
类型的代码,提供直接从文件到直接可以赋值给节点的纹理图片,或者从节点纹理直接获取处理后的纹理,所以笔者才起了创建这个静态函数库的想法。
(会持续更新最新修改版本,另外请注意Godot版本)
# =============================================
# 名称:textureDB
# 类型:静态函数库
# 描述:一些简化处理Image、Texture的静态函数
# 作者:巽星石
# Godot版本:v4.2.1.stable.official [b09f793f5]
# 创建时间:2024年2月8日22:48:38
# 最后修改时间:2024年2月9日02:02:58
# =============================================
class_name textureDB
enum ImageType{JPG,PNG,WEBP} # 支持存储的图片类型
# 直接从路径加载图片并返回ImageTexture
static func load_texture(img_path:String) -> ImageTexture:
var texture = ImageTexture.new()
var img = Image.load_from_file(img_path)
texture = texture.create_from_image(img)
return texture
# 水平翻转Texture2D
static func flip_x_texture(texture:Texture2D) -> ImageTexture:
var new_texture = ImageTexture.new()
var img = texture.get_image()
img.flip_x()
new_texture = new_texture.create_from_image(img)
return new_texture
# 垂直翻转Texture2D
static func flip_y_texture(texture:Texture2D) -> ImageTexture:
var new_texture = ImageTexture.new()
var img = texture.get_image()
img.flip_y()
new_texture = new_texture.create_from_image(img)
return new_texture
# 创建并返回原图片的灰度图
static func gray_scale_texture(texture:Texture2D) -> ImageTexture:
var new_texture = ImageTexture.new()
var img = texture.get_image()
for x in range(img.get_width()):
for y in range(img.get_height()):
var old_color = img.get_pixel(x,y)
var gray = (old_color.r + old_color.g + old_color.b)/3
var new_color = Color(gray,gray,gray,old_color.a)
img.set_pixel(x,y,new_color)
new_texture = new_texture.create_from_image(img)
return new_texture
# 获取并返回Texture2D的一个局部矩形区域
static func get_region(texture:Texture2D,region: Rect2i) -> ImageTexture:
var new_texture = ImageTexture.new()
var img = texture.get_image()
img = img.get_region(region)
new_texture = new_texture.create_from_image(img)
return new_texture
# 为图片添加边框
static func draw_border(texture:Texture2D,border_size:PackedInt32Array = [10,10,10,10],border_color:Color=Color.WHITE) -> ImageTexture:
var new_texture = ImageTexture.new()
# 1.通过原图和边框尺寸计算新图的尺寸
var old_img = texture.get_image() # 原图片
var new_img = Image.new() # 新图片
# 新的尺寸 = 原图片尺寸 + 边框尺寸
var new_size = old_img.get_size() + Vector2i(border_size[1] + border_size[3],border_size[0] + border_size[2])
# 2.通过新尺寸构造新的Image
new_img = new_img.create(new_size.x,new_size.y,false,Image.FORMAT_RGBA8)
new_img.fill(border_color) # 填充整个纹理区域为边框颜色
# 3.在新图的指定位置绘制原图
var rect = old_img.get_used_rect() # 原图的纹理区域
var pos = Vector2i(border_size[3],border_size[0]) # 起始位置
new_img.blit_rect(old_img,rect,pos) # 将原图绘制到新Image的指定区域
# 4.通过新Image构造ImageTexture
new_texture = new_texture.create_from_image(new_img)
return new_texture
# 创建纯色块的ImageTexture
static func color_block(size:Vector2,color:Color=Color.WHITE) -> ImageTexture:
var new_texture = ImageTexture.new()
var img = Image.new()
img = img.create(size.x,size.y,false,Image.FORMAT_RGBA8)
img.fill(color)
new_texture = new_texture.create_from_image(img)
return new_texture
# 创建棋盘格的ImageTexture
static func checker_board(img_size:Vector2i,cell_size:Vector2i=Vector2i(10,10),color1:Color=Color.WHITE,color2:Color=Color.BLACK) -> ImageTexture:
var new_texture = ImageTexture.new()
var img = Image.new()
img = img.create(img_size.x,img_size.y,false,Image.FORMAT_RGBA8)
# 计算所需要填充的数量
var grid_size = ceil(img_size / cell_size)
for x in range(grid_size.x):
for y in range(grid_size.y):
var rect = Rect2i(cell_size * Vector2i(x,y),cell_size)
if (x % 2 == 0 and y % 2 == 0) or (x % 2 == 1 and y % 2 == 1): # 奇数行奇数列,或者偶数行偶数列
img.fill_rect(rect,color1)
else:
img.fill_rect(rect,color2)
new_texture = new_texture.create_from_image(img)
return new_texture
# 直接将Texture2D保存为本地图片文件
static func save_texture(texture:Texture2D,file_path:String,img_type:ImageType=ImageType.JPG) -> void:
var img = texture.get_image()
match img_type:
ImageType.JPG:
img.save_jpg(file_path)
ImageType.PNG:
img.save_png(file_path)
ImageType.WEBP:
img.save_webp(file_path)
# 生成Image的缩略图
static func create_thumb(img:Image,size:Vector2) -> ImageTexture:
var texture = ImageTexture.new()
var old_size = img.get_size() # 原图尺寸
var aspect_ratio = old_size.aspect()
# 原图比缩略图宽或高时
if old_size.x > size.x or old_size.y > size.y:
if old_size.x > old_size.y: # 图片水平方向比较长
var new_w = size.x
var new_h = size.x / aspect_ratio
img.resize(new_w,new_h)
else:
var new_h = size.y
var new_w = size.y * aspect_ratio
img.resize(new_w,new_h,Image.INTERPOLATE_LANCZOS)
texture = texture.create_from_image(img)
return texture
# 生成指定路径文件的缩略图
static func create_thumb_from_file(img_path:String,size:Vector2) -> ImageTexture:
var texture = ImageTexture.new()
if img_path.get_extension() in ["png","jpg","svg"]:
var img = Image.load_from_file(img_path)
if img:
texture = create_thumb(img,size)
return texture
else:
return null
我们创建一个测试场景,添加一个TextureRect
控件。
并设定如下:
为根节点创建如下代码:
extends Control
@onready var texture_rect = $TextureRect
func _ready():
# 从文件加载图片
texture_rect.texture = textureDB.load_texture("res://icon.svg")
运行后就可以看到图片被正确加载,这种直接加载图片文件为纹理的形式,比构造ImageTexture
和Image
要简化的多了。
为了更好的展示图片处理效果,我们使用一张更大更复杂的图片。下面是原图加载后的效果:
修改设置如下:
根节点代码修改如下:
extends Control
@onready var texture_rect = $TextureRect
func _ready():
var img_path = "C:/Users/Lenovo/Pictures/Screenshots/屏幕截图 2024-02-06 150512.png"
# 从文件加载图片
var texture = textureDB.load_texture(img_path)
# 赋值水平翻转后的图片
texture_rect.texture = textureDB.flip_x_texture(texture)
运行后的效果:
可以看到图片被水平翻转,而且没有涉及Image
的底层操作。
垂直翻转的代码很类似,只需要将flip_x_texture
改为flip_y_texture
就可以了。
extends Control
@onready var texture_rect = $TextureRect
func _ready():
var img_path = "C:/Users/Lenovo/Pictures/Screenshots/屏幕截图 2024-02-06 150512.png"
# 从文件加载图片
var texture = textureDB.load_texture(img_path)
# 赋值水平翻转后的图片
texture_rect.texture = textureDB.flip_y_texture(texture)
垂直翻转效果:
通过get_region
可以获取相应纹理的的一个局部。
extends Control
@onready var texture_rect = $TextureRect
func _ready():
var img_path = "C:/Users/Lenovo/Pictures/Screenshots/屏幕截图 2024-02-06 150512.png"
# 从文件加载图片
var texture = textureDB.load_texture(img_path)
# 赋值局部裁切图片
texture_rect.texture = textureDB.get_region(texture,Rect2i(100,100,500,500))
效果如下:
可以应用于用户头像、封面图片裁切等场景。
在图片处理中有时候需要描边或绘制边框,draw_border
可以为原图外部添加四个边上的描边,而且可以设定每个边不一样的宽度。
extends Control
@onready var texture_rect = $TextureRect
func _ready():
var img_path = "C:/Users/Lenovo/Pictures/Screenshots/屏幕截图 2024-02-06 150512.png"
# 从文件加载图片
var texture = textureDB.load_texture(img_path)
# 赋值添加描边效果的图片
texture_rect.texture = textureDB.draw_border(texture)
默认的10像素边框:
可以自定义各个边的尺寸,顺序为:上右底左。
extends Control
@onready var texture_rect = $TextureRect
func _ready():
var img_path = "C:/Users/Lenovo/Pictures/Screenshots/屏幕截图 2024-02-06 150512.png"
# 从文件加载图片
var texture = textureDB.load_texture(img_path)
# 赋值添加描边效果的图片
texture_rect.texture = textureDB.draw_border(texture,[200,100,200,100])
自定义边框宽度效果:
另外,边框颜色也可以自定义:
extends Control
@onready var texture_rect = $TextureRect
func _ready():
var img_path = "C:/Users/Lenovo/Pictures/Screenshots/屏幕截图 2024-02-06 150512.png"
# 从文件加载图片
var texture = textureDB.load_texture(img_path)
# 赋值添加描边效果的图片
texture_rect.texture = textureDB.draw_border(texture,[200,100,200,100],Color.YELLOW_GREEN)
color_block
指定一个大小和颜色,就可以直接创建一个纯色块图片。默认为白色。
extends Control
@onready var texture_rect = $TextureRect
func _ready():
# 赋值纯色块
texture_rect.texture = textureDB.color_block(Vector2(200,200))
checker_board
用于参数化的创建棋盘格纹理,可以看做是我的第一个纹理图片生成函数,当然基于CanvasItem的绘制函数,已经创建过棋盘格了。
extends Control
@onready var texture_rect = $TextureRect
func _ready():
# 赋值棋盘格
texture_rect.texture = textureDB.checker_board(Vector2i(100,100),Vector2i(10,10))
extends Control
@onready var texture_rect = $TextureRect
func _ready():
# 赋值棋盘格
texture_rect.texture = textureDB.checker_board(Vector2i(100,100),Vector2i(10,10),Color.AQUA,Color.AQUAMARINE)
基于每个像素点RGB值相加除以3的做法,相对效率不是太高。但算勉强实现,使用多线程可能会加速一些。不过确实可以实现图片处理并输出为本地文件,一般使用还是用Shader实现吧,效率高多了。
extends Control
@onready var texture_rect = $TextureRect
func _ready():
var img_path = "C:/Users/Lenovo/Pictures/Screenshots/屏幕截图 2024-02-06 150512.png"
# 从文件加载图片
var texture = textureDB.load_texture(img_path)
# 赋值灰度图
texture_rect.texture = textureDB.gray_scale_texture(texture)
(等待施工…2024年2月9日01:37:37)
(等待施工…2024年2月9日01:37:37)