dimanche 12 février 2012

Créer UIImages à partir de données TGA

UIImage ne supporte pas un éventail aussi large de types de fichiers que ne NSImage en Cocoa. C'est compréhensible, étant donné la nature différente des dispositifs qu'ils courent, cependant il ya des moments où vous voulez charger des données dans un format qui n'est pas directement pris en charge par UIImage. Ce qui est arrivé récemment tout en expérimentant avec la création d'un chargeur de modèle Milkshape 3D pour une utilisation dans le développement de jeux iPhone. Milkshape utilise des fichiers Targa et PCX pour la texture, et aucun de ces formats est pris en charge par UIImage.

Je n'ai pas abordé les fichiers PCX, mais j'ai écrit une catégorie sur UIImage pour vous permettre d'instancier un objet à partir de données UIImage Targa stockées dans un fichier TGA. Cette version ne supporte pas les fichiers encodés RLE, mais généralement pour des modèles de jeu, RLE n'est pas codé. Si vous devez réduire la taille de votre exécutable image, passer comme un éclair les données non compressées TGA permettra d'économiser environ la même quantité de chambre. Si vous cherchez à faire un jeu, je n'aurais probablement pas recommandé compressant les images du tout sauf si vous êtes très proche de la limite que dix meg qui empêche les gens de télécharger votre jeu sur les réseaux 3G et Edge, puisque vous aurez à Développer le traitement des cycles pour décompresser lors du lancement ou de temps de chargement.

Vous pouvez trouver la catégorie et un projet Xcode qui montre comment il peut être utilisé dans le référentiel iPhone Bits plus moins Google Code.

Ceci est une première ébauche et il ya place susceptible d'amélioration. Il ya une certaine inefficacité connue de cette catégorie. Par exemple, la commande de l'iPhone d'octet natif est BGRA, et est donc Targa, ce code, cependant, convertit les données RVB au Targa, et probablement sous le capot, c'est UIImage reconversion BGRA. Je suis assez sûr Core Graphics fournit un moyen d'éviter cette conversion, mais n'ont pas le temps de le recherche dans l'immédiat. Aussi, si votre seul usage de l'image Targa va être en OpenGL, vous voulez probablement sauter cette catégorie tout à fait et il suffit de charger les données bitmap en OpenGL directement. Cette catégorie combinée avec la Texture2D partir des exemples de code d'Apple donne certainement un moyen facile de configurer un environnement échafaudage pour le développement précoce.

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; // skip first two bytes

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

// Targa is BGR, swap to RGB
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;
}


// Targa uses more standard Y axis, so need to swap top & bottom bytes
// We can swap 32 bits at a time rather than going byte by byte
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



Aucun commentaire: