Creating texture in XCode from Unity pixel data

Hey, I’ve been trying to do this for awhile now, but I can’t seem to create the texture properly! What I want is to pass the pixel data (raw texture data) from Unity to XCode. I believe this part is fine. In XCode I want to create a UIImage from the pixel data and I believe this is where I’m having the problem.

In Unity I do this:

	// Create the pixel array for the plugin to write into at startup    
    	m_Pixels = m_Texture.GetPixels ();
    	// "pin" the array in memory, so we can pass direct pointer to it's data to the plugin,
    	// without costly marshaling of array of structures.
    	m_PixelsHandle = GCHandle.Alloc(m_Pixels, GCHandleType.Pinned);
     _sendEmail(m_PixelsHandle.AddrOfPinnedObject(),m_Texture.width,m_Texture.height);

and in XCode I do this:

float* imageData = reinterpret_cast<float*>(texture); //texture is (void*) pixel data from unity!
NSInteger myDataLength = width * (height) * 4;
	CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, imageData, myDataLength, NULL);
	// prep the ingredients
	int bitsPerComponent = 8;
	int bitsPerPixel = 32;
	int bytesPerRow = 4 * width;
	CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
	CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
	// make the cgimage
	CGImageRef imageRef = CGImageCreate(width, height, bitsPerComponent, bitsPerPixel, bytesPerRow, CGColorSpaceCreateDeviceRGB(), bitmapInfo, provider, NULL, true, renderingIntent);
	// then make the uiimage from that
	uint32_t* pixels = (uint32_t *)malloc(myDataLength);
	CGContextRef context = CGBitmapContextCreate(pixels, width, height, bitsPerComponent, bytesPerRow, CGImageGetColorSpace(imageRef),
												 kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst);
	CGContextTranslateCTM(context, 0.0, height);
	CGContextScaleCTM(context, 1.0, -1.0);
	CGContextDrawImage(context, CGRectMake(0.0, 0.0, width, height), imageRef);   
	CGImageRef outputRef = CGBitmapContextCreateImage(context);
	UIImage *myImage = [UIImage imageWithCGImage:outputRef];
	free(pixels);

In Unity the texture has read/write enabled and it’s an ARGB format (I believe this and RGB are the only acceptable formats to read data from?)

Any help appreciated!

row - column order might potentially be different or unity might upon marshaling have a different color channel order than CoreGraphics expects (ie different than OrderDefault for example)

An easy way to ensure you don’t have problems would be using encode to png and send that bytes[ ] array over and using that on the other end to load the png again as png is a well defined format, unlike texture - pixmap data.

That way you can also avoid the problem you have with array of struct, as it will be byte[ ] and thus can just be pushed out. Pinning there is really not of that much use as the pin can’t be reused at all, unsure if the overhead is really that much smaller on an array of struct which is a continues datablob unlike an array of Object

That did the trick, thanks! Here’s what I did if anyone is interested:

In Unity:

byte[] bytes = m_Texture.EncodeToPNG();
_sendEmail(bytes,m_Texture.width,m_Texture.height);

In C#:

- (void) sendEmailWithTexture:(UInt8*)texture Width:(int)width Height:(int)height
{
	NSInteger myDataLength = width * height * sizeof(UInt8);
	NSData* imageData = [[NSData alloc] initWithBytes:(void*)texture length:myDataLength];
	UIImage* image = [[[UIImage alloc] initWithData:imageData] autorelease];
}

Just to explain what’s wrong with the original code, you need to convert the floats to RGBA 8-bit components. You’d loop the array and multiply each float value by 255 and store it into a bitmap.

Ahh, that makes sense, thanks :slight_smile: