Rotate Texture by 90 degrees

From AwkwardTV
Revision as of 09:28, 8 June 2007 by Axxr (talk | contribs)
Jump to: navigation, search


Because I needed a Vertical Progressbar, I had to get images of the stock Progress graphics rotate by 90 degrees. With some help from alan, this is the result.

Texture Cache

Since we don't want to have to do this stuff everytime our plugin loads, we'll use the Texture cache.

- (BRTexture*)loadImageAndRotate:(NSString*)path
  NSString* cacheName = [NSString stringWithFormat:@"%iROT_%@", 
                                                 [ [path lastPathComponent] 
                                                        stringByDeletingPathExtension] ]; 
  BRTexture* texture = [[self scene] cachedTextureForKey: cacheName];

The first line generates a cache name, by appending the filename ( [path lastPathComponent] ) without its extension (stringByDeletingPathExtension) to the string "90ROT_". The scene is then asked for a cached Texture with that name. If we do this the first time it will return nil, so we know we have to generate it.

if(texture == nil)
	NSURL * imageURL = [NSURL fileURLWithPath: path];
	CGImageRef image = CreateImageForURL( imageURL );
	CIImage* img = [CIImage imageWithCGImage:image];

The first step is to get a URL from the path and load an CGImageRef image by using the Backrow function CreateImageForURL. After that, an CIImage is created from that CGImageRef for using the actual transformation.


For the rotation I used the CIFilter class from the QuartzCore.Framework, so you'll have to include that into your project. CIFilters are created by name, so you have to know that. For the rotation I used the CIAffineTransformation Filter, which can scale / rotate and translate an Image.

CIFilter *transform = [CIFilter filterWithName:@"CIAffineTransform"];
[transform setValue:img forKey:@"inputImage"];
NSAffineTransform *affineTransform = [NSAffineTransform transform];
[affineTransform rotateByDegrees:90];
[transform setValue:affineTransform forKey:@"inputTransform"];
CIImage * result = [transform valueForKey:@"outputImage"];

The Parameter for the Filter are supplied via key-value pairs, the affinetransform filter takes an input image and the transformation itself, which is an NSAffineTransform. The transform itself consists of a mere 90 degrees rotation.

Back Translation

Because the rotation is not around 0,0 we have to reset the translation.

CGRect extent = [result extent];
transform = [CIFilter filterWithName:@"CIAffineTransform"];
affineTransform = [NSAffineTransform transform];
[affineTransform translateXBy:-extent.origin.x
[transform setValue:affineTransform forKey:@"inputTransform"];
[transform setValue:result forKey:@"inputImage"];
result = [transform valueForKey:@"outputImage"];

First, we take the current extents of the image, resupply these into another affineTransformation and transform the image again.

After these steps the origin of the image is back to 0,0 but because of the precision of float, the image is now slightly larger then we would expect. If for instance the original image was 28 by 15 pixels, we might now have a size of 28 by 16 pixels, which can be quite ugly if we depend on the size.


Therefor we have to crop the image to the correct size which would be size.width=org.height and size.y=org.width

transform = [CIFilter filterWithName:@"CICrop"];
[transform setValue:[CIVector vectorWithX:0.0 
                                        W:orgImgSize.size.width] forKey:@"inputRectangle"];
[transform setValue:result forKey:@"inputImage"];
result = [transform valueForKey:@"outputImage"];