Rotate a Color[] at intervals of 90 degrees

Hello. Extracting a Color of a Texture2D using Texture2D.GetPixels(), I was wondering if anyone had any explanation of how to then effectively ‘rotate’ this color array by 90 degree intervals (90, 180, 270, 360, etc, etc). This information is not for display or rendering in the GUI or scene, it is only for information sampling for another process. Many thanks.

It might also be valid to point out that the input image is always power-of-two and square!

A simple way is to copy the array to a temporary array, then copy the temporary array back to the first array while swapping the x and y elements. Assuming a 2D array for the sake of clarity:

for (var x = 0; x < size; x++) {
    for (var y = 0; y < size; y++) {
        colors[x, y] = tempColors[y, x];
    }
}

Since you have a 1D array, you would use a bit of math instead, e.g. colors[x + y*size]. By the way, you should use Color32 instead of Color, since it’s faster and uses 4X less RAM.

Hey, the GetPixels() method returns an array that is read left to right from bottom to top and you would like to rotate the array, so that the information it contains corresponds to an image that would effectively be rotated?

I will provide you with a block of code that I believe will help you to achieve this:

public class NewBehaviourScript : MonoBehaviour {

	//if we assume this is a 3x3 square whose top row is 1->3 and bottom row 7->9

 	int[] someNumbers = {1,2,3,4,5,6,7,8,9};
	int[] rotatedNumbers = new int[9] ;
	int count = 0;

	//What we want is to turn this image 90 degrees clockwise which means 
    //the array would become {7,4,1,  6,5,2,  9,6,3}
	//if you draw this out on paper, it's easier to see why!
	
	
	void Start()
	{
		//here we take the size of the array

		int sizeOfArray = someNumbers.Length;

		//this is the width which will be the same as the height

		int widthOfArray =(int) Mathf.Sqrt(sizeOfArray);
		
		
		//start a loop which begins at the left column

		for(int j=0; j<widthOfArray; j++)
		{
			//this takes the first value in each column 
           //and places it into the new array in order

			for (int i =1; i<= widthOfArray; i++)
			{
				rotatedNumbers[count] = someNumbers[(sizeOfArray-(widthOfArray*i))+j];
				count++;
			} 
		}

		//rotatedNumbers will now contain {7,4,1,6,5,2,9,6,3} in that order
	}
}

Please let me know if I have misunderstood your question, also this may not be the most elegant solution to your problem but I hope it helps!

Here’s just some typical example code. It’s possible it could save someone some time.

use a trivial routine int XY(x,y) to make the code very simple.

In Unity coords, to go -90 degrees, it is…

x, y = y, (size-1-x)

.
and to go +90 degrees, it is…

x, y = (size-1-y), x

.
(To check that, simply draw a 10x10 grid of dots on a piece of paper, mark a point, and rotate the paper either way.)

(Obviously “size-1” is just the highest index, i.e. if it’s 640 square the highest index is 639.)

Note that almost always, you want to resize the texture. (Example, you’re saving an avatar to Facebook or something, so you want it as 256.256.) This is always done using TextureScale by Eric H. An example is shown in this code and the URL is there if you don’t have it yet.

int desiredSize; // global used by the trivial XY() routine below

public string CreateAndSaveImageNow()
	{
	Debug.Log("needsToBeRotatedDegrees is here ... " +needsToBeRotatedDegrees);
	// that global would be set by, for example, your camera code
	
	if ( camTexture.width < camTexture.height )
		desiredSize = camTexture.width;
	else
		desiredSize = camTexture.height;
	
	Debug.Log("desired heigh==width is ... " +desiredSize);
	
	Texture2D virtualPhoto =
		new Texture2D(desiredSize, desiredSize, TextureFormat.RGB24, false);
	
	// using the handy "four argument" form of GetPixels, you can trivially
	// take "only a square" from a rectangular image:
	// (note, GetPixels32 does not have the handy "four argument" form.)
	
	Color[] origPixels = camTexture.GetPixels(0,0,desiredSize,desiredSize);
	
	// now rotate as needed either -90, 0, 90
	
	Color[] rotPixels = new Color[ origPixels.Length ];
	
	for (var x = 0; x < desiredSize; x++)
		for (var y = 0; y < desiredSize; y++)
			{
			if ( needsToBeRotatedDegrees == 0 )
				rotPixels[ XY(x, y) ] = origPixels[ XY(x, y) ];
			
			if ( needsToBeRotatedDegrees == 270 || needsToBeRotatedDegrees == -90 )
				rotPixels[ XY(x, y) ] = origPixels[ XY(y, (desiredSize-1-x)) ];
			
			if ( needsToBeRotatedDegrees == 90 )
				rotPixels[ XY(x, y) ] = origPixels[ XY((desiredSize-1-y), x) ];
			}
	
	virtualPhoto.SetPixels( rotPixels );
	virtualPhoto.Apply();
	
	Debug.Log("In this example, we are changing to 256.256...");
	// like every Unity project we use TextureScale by Eric H.  Get the file at:
	// http://wiki.unity3d.com/index.php/TextureScale
	TextureScale.Bilinear (virtualPhoto, 256,256);
	
	byte[] bytes;
	bytes = virtualPhoto.EncodeToPNG();
	System.IO.File.WriteAllBytes( OurTempSquareImageLocation(), bytes );
	
	return OurTempSquareImageLocation();
	}

private int XY( int x, int y )
	{
	// this trivial routine just returns the "1d array" version of x,y
	// using the global width (==height) of the arrays in question
	return ( x + y * desiredSize );
	}

private string OurTempSquareImageLocation()
	{
	string r = Application.persistentDataPath + "/droidSquarePhoto.png";
	return r;
	}

Hope it saves someone some time, cheers

You only really need an algorithm for one of the rotations. The other ones are just reversals:

using UnityEngine;
using System.Linq;
using System.Collections.Generic;

public static class Texture2DExtensions 
{
	public enum Rotation { Left, Right, HalfCircle }
	public static void Rotate(this Texture2D texture, Rotation rotation)
	{
		Color32[] originalPixels = texture.GetPixels32();
		IEnumerable<Color32> rotatedPixels;

		if (rotation == Rotation.HalfCircle)
			rotatedPixels = originalPixels.Reverse();
		else
		{	
			// Rotate left:
			var firstRowPixelIndeces = Enumerable.Range(0, texture.height).Select(i => i * texture.width).Reverse().ToArray();
			rotatedPixels = Enumerable.Repeat(firstRowPixelIndeces, texture.width).SelectMany(
				(frpi, rowIndex) => frpi.Select(i => originalPixels[i + rowIndex])
			);

			if (rotation == Rotation.Right)
				rotatedPixels = rotatedPixels.Reverse();
		}

		texture.SetPixels32( rotatedPixels.ToArray() );
		texture.Apply();
	}
}