You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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);
    }
    
}

问题根源

  1. 坐标逻辑错误:sourceRect.position是UI的世界坐标,和Texture的像素坐标不匹配,不能直接作为裁剪起始点。
  2. 裁剪逻辑缺失:直接将原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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 11:15:37