Travis Griggs
Travis Griggs

Reputation: 22252

How to encode a UIImage for JSON transmission?

I'm trying to build up an NSMutableDictionary to be converted to be json'ed. One of my key-values are the bytes for a png representation of a picture. So I have something like

NSMutableDictionary *jsonDict = [[NSMutableDictionary alloc] init];
....
if ([self hasPhoto])
{
    result[@"photo"] = UIImagePNGRepresentation(self.photo);
}

This later blows up, because NSJSONSerialization doesn't do things like NSData objects which is what UIImagePNGRepresenation returns. What is a good way to encode the data? Just UTF8'ing would likely be bad. I'm not that familiar with the guts of what are legal string representations in json.

Update:

I ended up finding this link about using Apple's builtin but unadvertised functions. The code was longer, but I was 2 files less:

NSData *data = UIImageJPEGRepresentation(self.photo, 0.5);
NSString *base64 = nil;
NSUInteger sourceLength = data.length;
NSUInteger encodeBufferLength = ((sourceLength + 2) / 3) * 4 + 1;
char *encodeBuffer = malloc(encodeBufferLength);
int encodedRealLength = b64_ntop(data.bytes, sourceLength, encodeBuffer, encodeBufferLength);
if (encodedRealLength >= 0)
{
    base64 = [[NSString alloc] initWithBytesNoCopy: encodeBuffer length: encodedRealLength + 1 encoding: NSASCIIStringEncoding freeWhenDone: YES];
}
else
{
    free(encodeBuffer);
}
result[@"photo-jpeg"] = base64;

This also runs about 7X faster than the Base64 solution below. Not that speed mattered AT ALL in this particular case, but someone asked.

Upvotes: 2

Views: 1368

Answers (2)

memmons
memmons

Reputation: 40502

Typically, images are encoded as a base64 string for JSON. There is no built-in way to encode NSData to a base64 string, but the algorithm to do so is fairly well known. Create an NSData category like so:

static char encodingTable[64] = {
    'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
    'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
    'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
    'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/' };

@implementation NSData (Base64)

- (NSString *) base64EncodingWithLineLength:(unsigned int) lineLength {
    const unsigned char *bytes = [self bytes];
    NSMutableString *result = [NSMutableString stringWithCapacity:[self length]];
    unsigned long ixtext = 0;
    unsigned long lentext = [self length];
    long ctremaining = 0;
    unsigned char inbuf[3], outbuf[4];
    short i = 0;
    short charsonline = 0, ctcopy = 0;
    unsigned long ix = 0;

    while( YES ) {
        ctremaining = lentext - ixtext;
        if( ctremaining <= 0 ) break;

        for( i = 0; i < 3; i++ ) {
            ix = ixtext + i;
            if( ix < lentext ) inbuf[i] = bytes[ix];
            else inbuf [i] = 0;
        }

        outbuf [0] = (inbuf [0] & 0xFC) >> 2;
        outbuf [1] = ((inbuf [0] & 0x03) << 4) | ((inbuf [1] & 0xF0) >> 4);
        outbuf [2] = ((inbuf [1] & 0x0F) << 2) | ((inbuf [2] & 0xC0) >> 6);
        outbuf [3] = inbuf [2] & 0x3F;
        ctcopy = 4;

        switch( ctremaining ) {
            case 1:
                ctcopy = 2;
                break;
            case 2:
                ctcopy = 3;
                break;
        }

        for( i = 0; i < ctcopy; i++ )
            [result appendFormat:@"%c", encodingTable[outbuf[i]]];

        for( i = ctcopy; i < 4; i++ )
            [result appendFormat:@"%c",'='];

        ixtext += 3;
        charsonline += 4;

        if( lineLength > 0 ) {
            if (charsonline >= lineLength) {
                charsonline = 0;
                [result appendString:@"\n"];
            }
        }
    }

    return result;
}

@end

Encoding for JSON then becomes trivial:

NSData *imageData = UIImagePNGRepresentation(self.photo);
NSString *base64String = [imageData base64EncodingWithLineLength:0];
result[@"photo] = base64String;

Note that images taken with iOS devices are quite large. The number of bytes you are transmitting is equal to the width x height x 3. For example an iPhone 5 has an 8MP camera, that is 3264 x 2448 x 3 = 23MB of data. You almost never want to transmit that much data via JSON. So, you'll want to crop the photo or resize it down to something more manageable before sending.

Upvotes: 1

ArunMak
ArunMak

Reputation: 398

You need to convert your image to base64 string .So that you can pass transmit using JSON. Here is the link to download base64 class files.

Then initialize this in your view controller.m:

[Base64 initialize];

After that convert your image to NSData and use this code:

NSString   *strEncoded = [Base64 encode:webDat];

where webdat is an NSData.

Upvotes: 3

Related Questions