从 Web 服务中读取二进制图像数据并转换为 UIImage

4
我在我的iPhone应用程序中使用了一个Web服务。该Web服务方法返回一个响应,其中包含多个字段(例如ID、描述等)。其中一个字段包含二进制图像数据,我需要将其转换为UIImage在我的iPhone应用程序中。
我成功地使用NSXMLParser从XML响应中提取数据。在XMLParser的parser:foundCharacters:选择器中,它给出了指向每个字段中字符串的NSString*。由于这是一个字符串,所以当我遇到图像字段时,这就是我读取图像数据的方法:
UIImage *img = [[UIImage alloc] initWithData:[string dataUsingEncoding:NSUTF8StringEncoding]];

但是在这一行之后,img变量仍然为“nil”。看起来XML字符串中的数据与转换不兼容。我在这里做错了什么?(我能够将其他字段读入我的变量中,但不能读取此图像数据字段)
提前致谢。
2个回答

5

在参考fbrereto的回答后,我使用了该链接中的代码示例将字符串转换为NSData:http://www.cocoadev.com/index.pl?BaseSixtyFour(滚动到MiloBird用户的代码示例)。现在我可以成功构建图像。

它使用Objective-C类别向NSData类添加选择器+(id)dataWithBase64EncodedString:(NSString *)string;。这是我从上述链接中提取的必要代码示例:

//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

谢谢大家!

我和你遇到了完全相同的问题。很高兴我找到了你的答案,但是我并不真正理解代码以及如何使用它。我有一个从 Web 服务解析出来的字符串 currentElementValue,我想将其转换为 NSData,以便我可以进一步转换为图像。你能给我一些建议吗?谢谢。 - alin
1
也许这个答案已经很晚了。但是你可以使用示例中提供的方法,并像这样调用它:NSData *data = [NSData dataWithBase64EncodedString:currentElementValue]; UIImage *img = [UIImage imageWithData:data]; - ravinsp

1

NSString 的技巧在于它包含的数据有一个隐式编码。然而,你接收到的图片很可能是以二进制数据或某种无损编码(例如 base64)的格式,这些格式不会正确转换。因此,关键是要确保你不让 NSString 执行任何编码转换,否则你的图像数据将被破坏。我建议你尝试使用类似 getBytes:maxLength:usedLength:encoding:options:range:remainingRange 的 API,而不是使用 dataUsingEncoding:。虽然比 dataUsingEncoding: 更复杂,但我认为它会给你提供所需的灵活性,让你从 NSString 中获取仅仅数据,而不会多余的东西。


感谢您宝贵的想法,但我需要知道字符串中的字节数。我该如何知道呢?无论是[string length]还是[string lengthOfBytesUsingEncoding]都涉及字符编码。如果我能知道字节长度,我也许可以使用[string getCString]来获取原始字节。再次感谢。 - ravinsp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接