概述
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 textureDBenum 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)/3var 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.通过新尺寸构造新的Imagenew_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构造ImageTexturenew_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.xvar new_h = size.x / aspect_ratioimg.resize(new_w,new_h)else:var new_h = size.y var new_w = size.y * aspect_ratioimg.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 textureelse:return null
用法示例
我们创建一个测试场景,添加一个TextureRect
控件。
并设定如下:
加载图片文件到节点
为根节点创建如下代码:
extends Control@onready var texture_rect = $TextureRectfunc _ready():# 从文件加载图片texture_rect.texture = textureDB.load_texture("res://icon.svg")
运行后就可以看到图片被正确加载,这种直接加载图片文件为纹理的形式,比构造ImageTexture
和Image
要简化的多了。
水平翻转图片
为了更好的展示图片处理效果,我们使用一张更大更复杂的图片。下面是原图加载后的效果:
修改设置如下:
根节点代码修改如下:
extends Control@onready var texture_rect = $TextureRectfunc _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 = $TextureRectfunc _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 = $TextureRectfunc _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 = $TextureRectfunc _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 = $TextureRectfunc _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 = $TextureRectfunc _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 = $TextureRectfunc _ready():# 赋值纯色块texture_rect.texture = textureDB.color_block(Vector2(200,200))
棋盘格
checker_board
用于参数化的创建棋盘格纹理,可以看做是我的第一个纹理图片生成函数,当然基于CanvasItem的绘制函数,已经创建过棋盘格了。
extends Control@onready var texture_rect = $TextureRectfunc _ready():# 赋值棋盘格texture_rect.texture = textureDB.checker_board(Vector2i(100,100),Vector2i(10,10))
通过设定两个颜色,可以绘制彩色棋盘格。
extends Control@onready var texture_rect = $TextureRectfunc _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 = $TextureRectfunc _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)