Reading binary image data from a web service into UIImage
I'm consuming a web service in my iPhone app. The web service method returns a response which has several fields (eg. ID, Description, etc..). One of these fields contains binary image data which I need to convert to UIImage in my iPhone application.
I'm using a NSXMLParser successfully to extract data from the XML response. In the parser:foundCharacters:
selector of the XMLParser, it gives a NSString*
pointing to the string within each field. Since this is a string, this is what I do to read image data when i encounter t开发者_如何转开发he image field:
UIImage *img = [[UIImage alloc] initWithData:[string dataUsingEncoding:NSUTF8StringEncoding]];
But img variable is still "nil" after this line. Seems like the data from XML string is not compatible with conversion. What am I doing wrong here? (I'm capable of reading other fields into my variables but not this image data field)
Thanks in advance..
Following fbrereto's answer, I managed to convert the string into NSData using a code sample at this link: http://www.cocoadev.com/index.pl?BaseSixtyFour (scroll to the code sample by MiloBird user). Now I can construct the image successfully.
It uses objective-c categories to add the selector + (id)dataWithBase64EncodedString:(NSString *)string;
to the NSData class. Here's the necessary code sample I extracted from the above link:
//MBBase64.h
@interface NSData (MBBase64)
+ (id)dataWithBase64EncodedString:(NSString *)string; // Padding '=' characters are optional. Whitespace is ignored.
@end
//MBBase64.m
static const char encodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
@implementation NSData (MBBase64)
+ (id)dataWithBase64EncodedString:(NSString *)string;
{
if (string == nil)
[NSException raise:NSInvalidArgumentException format:nil];
if ([string length] == 0)
return [NSData data];
static char *decodingTable = NULL;
if (decodingTable == NULL)
{
decodingTable = malloc(256);
if (decodingTable == NULL)
return nil;
memset(decodingTable, CHAR_MAX, 256);
NSUInteger i;
for (i = 0; i < 64; i++)
decodingTable[(short)encodingTable[i]] = i;
}
const char *characters = [string cStringUsingEncoding:NSASCIIStringEncoding];
if (characters == NULL) // Not an ASCII string!
return nil;
char *bytes = malloc((([string length] + 3) / 4) * 3);
if (bytes == NULL)
return nil;
NSUInteger length = 0;
NSUInteger i = 0;
while (YES)
{
char buffer[4];
short bufferLength;
for (bufferLength = 0; bufferLength < 4; i++)
{
if (characters[i] == '\0')
break;
if (isspace(characters[i]) || characters[i] == '=')
continue;
buffer[bufferLength] = decodingTable[(short)characters[i]];
if (buffer[bufferLength++] == CHAR_MAX) // Illegal character!
{
free(bytes);
return nil;
}
}
if (bufferLength == 0)
break;
if (bufferLength == 1) // At least two characters are needed to produce one byte!
{
free(bytes);
return nil;
}
// Decode the characters in the buffer to bytes.
bytes[length++] = (buffer[0] << 2) | (buffer[1] >> 4);
if (bufferLength > 2)
bytes[length++] = (buffer[1] << 4) | (buffer[2] >> 2);
if (bufferLength > 3)
bytes[length++] = (buffer[2] << 6) | buffer[3];
}
realloc(bytes, length);
return [NSData dataWithBytesNoCopy:bytes length:length];
}
@end
Thank you all!
The trick with NSString
is that there is an implicit encoding associated with the data it contains. The image you are receiving, however, is likely in a format that will not convert properly, as it is either binary data or some lossless encoding of binary data (e.g., base64). The trick, then, is to make sure you don't let NSString
perform any encoding conversions at all, otherwise your image data will be corrupted. Instead of using dataUsingEncoding:
I would try an API more like getBytes:maxLength:usedLength:encoding:options:range:remainingRange
. While more complex than dataUsingEncoding:
I think it'll give you the flexibility you need to get just the data from the NSString and nothing more.
精彩评论