UIImage doesn't support as wide a range of file types as
NSImage does in Cocoa . It's understandable, given the different natures of the devices they run on, however there are times when you will want to load data in a format that's not directly supported by
UIImage. This happened recently while experimenting with creating a Milkshape 3D model loader for use in iPhone game development. Milkshape uses Targa and PCX files for the texture, and neither of these formats is supported by
UIImage.
I haven't tackled PCX files, but I wrote a category on
UIImage to let you instantiate a
UIImage object from Targa data stored in a TGA file. This version doesn't support RLE encoded files, but generally for game models, RLE isn't encoded. If you need to save size in your image executable, zipping the uncompressed TGA data will save about the same amount of room. If you're looking at doing a game, I probably wouldn't recommend compressing the images at all unless you're very close to that ten meg limit that prevents people from downloading your game over 3G & Edge, since you'll have to expend processing cycles to decompress at launch or load time.
You can find the category and an Xcode project that shows how it can be used
in the iPhone Bits repository over at
Google Code.
This is a first draft and there is likely room for improvement. There are some known inefficiencies in this class. For example, the iPhone's native byte ordering is BGRA, and so is Targa's, This code, however, converts the Targa data to RGB, and likely under the hood,
UIImage is converting back to BGRA. I'm pretty sure Core Graphics provides a way to avoid this conversion, but don't have time to research it right now. Also, if your only use of the Targa image is going to be in OpenGL, you probably want to skip this category altogether and just load the bitmap data into OpenGL directly. This category combined with the
Texture2D from Apple's sample code certainly gives an easy way to setup a scaffold environment for early development.
UIImage-Targa.h#import <UIKit/UIKit.h>
@interface UIImage(Targa)
+(id)imageFromTGAFile:(NSString *)filename;
+(id)imageFromTGAData:(NSData *)data;
+(id)imageWithRawRGBAData:(NSData *)data width:(int)width height:(int)height;
@end
UIImage-Targa.m#import "UIImage-Targa.h"
void releaseImageData(void *info, const void *data, size_t size)
{
free((void *)data);
}
@implementation UIImage(Targa)
+(id)imageFromTGAFile:(NSString *)filename
{
NSData *data = [[NSData alloc] initWithContentsOfFile:filename];
id ret = [self imageFromTGAData:data];
[data release];
return ret;
}
+(id)imageFromTGAData:(NSData *)data
{
short imageHeight;
short imageWidth;
unsigned char bitDepth;
unsigned char imageType;
int colorMode;
long imageSize;
unsigned char *imageData;
unsigned char *bytes = (unsigned char *)[data bytes]+2;
memcpy(&imageType, bytes, sizeof(unsigned char));
if (imageType != 2 && imageType != 3)
{
NSException *exception = [NSException exceptionWithName:@"Unsupported File Format"
reason:@"Compressed TGA files are not supported yet"
userInfo:nil];
[exception raise];
}
bytes += ( (sizeof(unsigned char) * 2) + (sizeof(short) * 4));
memcpy(&imageWidth, bytes, sizeof(short));
bytes += 2;
memcpy(&imageHeight, bytes, sizeof(short));
bytes += 2;
memcpy(&bitDepth, bytes, sizeof(char));
bytes+=2;
colorMode = bitDepth / 8;
imageSize = imageWidth * imageHeight * colorMode;
long newDataLength = imageWidth * imageHeight * 4;
imageData = (unsigned char *)malloc(newDataLength);
memcpy(imageData, bytes, imageSize * sizeof(unsigned char));
long byteCounter = 0;
for (long i = 0; i < imageSize; i += colorMode)
{
long start = (byteCounter++ * 4);
imageData[start] = bytes[i+2];
imageData[start+1] = bytes[i+1];
imageData[start+2] = bytes[i];
imageData[start+3] = (colorMode == 4) ? bytes[i+3] : 1.0;
}
uint32_t *imageDataAsInts = (uint32_t *)imageData;
for (int y = 0; y < imageHeight / 2; y++)
{
for (int x = 0; x < imageWidth; x++)
{
uint32_t top = imageDataAsInts[y * imageWidth + x];
uint32_t bottom = imageDataAsInts[(imageHeight - 1 - y) * imageWidth + x];
imageDataAsInts[(imageHeight - 1 - y) * imageWidth + x] = top;
imageDataAsInts[y * imageWidth + x] = bottom;
}
}
NSData *swappedData = [[NSData alloc] initWithBytes:imageData length:newDataLength];
return [self imageWithRawRGBAData:swappedData width:imageWidth height:imageHeight];
}
+(id)imageWithRawRGBAData:(NSData *)data width:(int)width height:(int)height
{
const void * buffer = [data bytes];
CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, buffer, [data length], releaseImageData);
const int bitsPerComponent = 8;
const int bitsPerPixel = 4 * bitsPerComponent;
const int bytesPerRow = 4 * width;
CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
CGImageRef imageRef = CGImageCreate(width, height, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);
CGDataProviderRelease(provider);
UIImage *myImage = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
return myImage;
}
@end
No comments:
Post a Comment