Unity图片裁剪问题:使用Rect仅裁剪左下角,需批量处理
Unity图片裁剪问题修正
问题说明
刚接触C#,在Unity中尝试实现图片裁剪功能,计划用Rectangle信息作为裁剪依据,但目前只能裁剪出图片的左下角区域,目标是批量裁剪图片并保存到指定文件夹。
原代码
public class ImageCropper : MonoBehaviour { [SerializeField] Sprite oldImage; [SerializeField] GameObject newSize; //Select a Texture in the Inspector to change to Texture2D sourceTexture; RectTransform sourceRect; private string folder = "**FILEPATH**"; // Start is called before the first frame update void Start() { //Change the Texture to be the one you define in the Inspector sourceTexture = oldImage.texture; sourceRect = newSize.GetComponent<RectTransform>(); int x = Mathf.FloorToInt(sourceRect.position.x); int y = Mathf.FloorToInt(sourceRect.position.y); int width = Mathf.FloorToInt(sourceRect.rect.width); int height = Mathf.FloorToInt(sourceRect.rect.height); /*Debug.Log(sourceRect.position.x + " " + sourceRect.position.y + " " + sourceRect.rect.width + " " + sourceRect.rect.height); Debug.Log(x + " " + y + " " + width + " " + height);*/ Color[] pix = sourceTexture.GetPixels(); Texture2D newImage = new Texture2D(width, height); newImage.SetPixels(pix); newImage.Apply(); byte[] bytes = newImage.EncodeToPNG(); File.WriteAllBytes(folder + "/soldier1.png", bytes); } }
问题根源
- 坐标逻辑错误:
sourceRect.position是UI的世界坐标,和Texture的像素坐标不匹配,不能直接作为裁剪起始点。 - 裁剪逻辑缺失:直接将原Texture的所有像素传入新Texture,新Texture仅截取前
width*height个像素,自然只会得到左下角区域。
修正方案
以下代码解决了坐标转换和裁剪区域获取的问题,同时支持后续扩展批量裁剪:
using System.IO; using UnityEngine; public class ImageCropper : MonoBehaviour { [SerializeField] Sprite targetSprite; [SerializeField] RectTransform cropFrame; // UI上的裁剪框 [SerializeField] string saveFolder = "**FILEPATH**"; // 批量裁剪可扩展为Sprite数组 // [SerializeField] Sprite[] targetSprites; void Start() { // 先确保保存文件夹存在 if (!Directory.Exists(saveFolder)) { Directory.CreateDirectory(saveFolder); } // 单张裁剪示例,批量裁剪可循环遍历targetSprites数组 CropSprite(targetSprite, cropFrame); } void CropSprite(Sprite sprite, RectTransform cropFrame) { Texture2D sourceTex = sprite.texture; Rect spriteTexRect = sprite.rect; // Sprite在原Texture上的区域 RectTransform spriteRectTrans = sprite.rectTransform; // 将裁剪框的坐标转换为相对于Sprite的比例 Vector2 cropAnchorPos = cropFrame.anchoredPosition; Vector2 cropSize = cropFrame.rect.size; Vector2 spriteSize = spriteRectTrans.sizeDelta; // 计算裁剪区域在原Texture上的像素坐标 float xRatio = (cropAnchorPos.x + spriteSize.x / 2) / spriteSize.x; float yRatio = (cropAnchorPos.y + spriteSize.y / 2) / spriteSize.y; float widthRatio = cropSize.x / spriteSize.x; float heightRatio = cropSize.y / spriteSize.y; int startX = Mathf.FloorToInt(spriteTexRect.x + xRatio * spriteTexRect.width); int startY = Mathf.FloorToInt(spriteTexRect.y + yRatio * spriteTexRect.height); int cropWidth = Mathf.FloorToInt(widthRatio * spriteTexRect.width); int cropHeight = Mathf.FloorToInt(heightRatio * spriteTexRect.height); // 防止越界 startX = Mathf.Clamp(startX, 0, sourceTex.width); startY = Mathf.Clamp(startY, 0, sourceTex.height); cropWidth = Mathf.Clamp(cropWidth, 1, sourceTex.width - startX); cropHeight = Mathf.Clamp(cropHeight, 1, sourceTex.height - startY); // 获取指定区域的像素 Color[] cropPixels = sourceTex.GetPixels(startX, startY, cropWidth, cropHeight); Texture2D croppedTex = new Texture2D(cropWidth, cropHeight); croppedTex.SetPixels(cropPixels); croppedTex.Apply(); // 保存图片,用时间戳避免重名 string savePath = Path.Combine(saveFolder, $"cropped_{sprite.name}_{System.DateTime.Now.Ticks}.png"); File.WriteAllBytes(savePath, croppedTex.EncodeToPNG()); // 清理临时Texture Destroy(croppedTex); } }
关键修正点
- 使用
sourceTexture.GetPixels(startX, startY, width, height)重载,精准获取裁剪区域像素。 - 将UI裁剪框的坐标转换为相对于Sprite的比例,再映射到原Texture的像素坐标,解决坐标不匹配问题。
- 增加边界校验,避免裁剪区域超出Texture范围。
- 支持批量裁剪:只需将
targetSprite改为数组,循环调用CropSprite方法即可。
内容的提问来源于stack exchange,提问作者LoomLG
相关产品推荐
相关产品推荐

