Search code examples
unity-game-enginecanvastexture2d

Crop Image texture on WorldSpace Canvas using RectTransform on Overlay Canvas


I've been trying for several days to crop an Image texture (Board - originalImage in the code example) on WorldSpace Canvas using RectTransform(CropArea - cropArea in the code example) on Overlay Canvas.

enter image description here

The problem is that I can't find the correct coordinates of the cropArea on the original image.

I've tried with this:

        Texture2D croppedTexture = new Texture2D((int)cropArea.rectTransform.rect.width, (int)cropArea.rectTransform.rect.height);
        Texture2D originalTexture = (Texture2D) originalImage.mainTexture;
        
        croppedTexture.SetPixels(originalTexture.GetPixels((int)cropArea.rectTransform.anchoredPosition.x, (int)cropArea.rectTransform.anchoredPosition.y, (int)cropArea.rectTransform.rect.width, (int)cropArea.rectTransform.rect.height));
        croppedTexture.Apply();
        resultImage.texture = croppedTexture;

But the result image is not cropped properly. It is a bit to the left and a bit down.

enter image description here

Does anybody have an idea how can I achieve this?


Solution

  • I found I have to consider so many variables. Here is a simplified version.

    Need a new field: worldCanvas

    var cropRectTrans = cropArea.rectTransform;
    var origRectTrans = originalImage.rectTransform;
    var origRectSize = origRectTrans.sizeDelta;
    var pivot = origRectTrans.pivot;
    Texture2D originalTexture = (Texture2D)originalImage.mainTexture;
    
    // Scale pivot to pixel unit.
    
    pivot.Scale(origRectSize);
    
    // Get corners of the overlay rectangle in world space.
    // The canvas is "Screen Space Overlay", so these positions are
    // also the screen positions.
    
    var cropCorners = new Vector3[4];
    cropRectTrans.GetWorldCorners(cropCorners);
    
    // Transform the left-bottom and right-top corners to the space
    // of the original image. The translated position needs to be added
    // with the scaled pivot, so that we can obtain the coordinates
    // relative to the left-bottom corner of the image.
    
    var cam = worldCanvas.worldCamera;
    RectTransformUtility.ScreenPointToLocalPointInRectangle(
        origRectTrans, cropCorners[0], cam, out Vector2 lb);
    RectTransformUtility.ScreenPointToLocalPointInRectangle(
        origRectTrans, cropCorners[2], cam, out Vector2 tr);
    
    var point = lb + pivot;
    var size = tr - lb;
    
    // Scale the position and size if the image is scaled.
    
    var scale = new Vector2(
        originalTexture.width / origRectSize.x,
        originalTexture.height / origRectSize.y
    );
    point.Scale(scale);
    size.Scale(scale);
    
    // Finally we get the correct position and size in the original image space.
    
    Texture2D croppedTexture = new Texture2D((int)size.x, (int)size.y);
    croppedTexture.SetPixels(originalTexture.GetPixels(
        (int)point.x, (int)point.y, (int)size.x, (int)size.y));
    croppedTexture.Apply();
    resultImage.texture = croppedTexture;