Search code examples
iosimagesocketsnsdataoutputstream

Break image/jpeg into chunks and bind in nsdictionary for sending JSON in iOS


EDIT: I did not do a very good job of explaining for the server works and my apologies for the same. So here are two things in which the server works ( expects data from clients)

1) Server has a size limitation for receiving image data. It expects images to be broken up in chunks of byte array 2) Server expects to receive these chunks of byte array through JSON.

So I am assuming this translates to the following on the client side

1) I need to break the image in parts 2) Create a Byte array of each part 3) Bind those byte array with JSON and send with server

Once received by the server, those are constructed as an Image by the server.

I am trying to achieve the above mentioned goal by the following approach (I keep the image file in NSData, then I create a Byte Buffer and keep chunks of the image file's NSData in that buffer. Post that I bind this buffer with JSON )

Following is the code for above approach:

-(void)dividepacketId:(int)pktId fileData:(NSData*)dt //dt contain the NSData of image file {

Byte buffer[20480];
long long dtLength,from=0;
long long len=[dt length];
BOOL b=YES;
while (b)
{
    int k=0,indexCont=0;
    if(len>20480)
    {
      dtLength=20480;
    }
    else
    {
        dtLength=len;
        b=NO;
    }
    [dt getBytes:buffer range:NSMakeRange(from,dtLength)];

    NSData *imageData=nil;
    imageData = [NSData dataWithBytes:buffer length:dtLength];
    len=len-dtLength;
    from=from+dtLength;
    NSLog(@"sending buffer=%s legth of buffer=%lli len value=%lli",buffer,dtLength,len);   //everything is fine till here
    NSMutableDictionary *projectDictionary3 = [NSMutableDictionary dictionaryWithCapacity:1];
    [projectDictionary3 setObject:@"2100" forKey:@"Action"];
    [projectDictionary3 setObject:[NSString stringWithFormat:@"%i",pktId] forKey:@"PacketId"];
    [projectDictionary3 setObject:@"101" forKey:@"FileAction"];
    if(imageData!=nil)
    [projectDictionary3 setObject: imageData forKey:@"FData"];//data
    [projectDictionary3 setObject:[NSString stringWithFormat:@"%i",(int)dtLength] forKey:@"DataLength"];//data
    NSError *jsonSerializationError = nil;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:projectDictionary3 options:NSJSONWritingPrettyPrinted error:&jsonSerializationError]; //"here crashed"
    if(!jsonSerializationError)
    {
        NSString *serJSON = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
        NSLog(@"Serialized JSON: %@", serJSON);
    }
    else
    {
     NSLog(@"JSON Encoding Failed: %@", [jsonSerializationError localizedDescription]);
    }
code to send over stream
[self sendDataToServer:jsonData];

} //while loop

}

Here is the challenge. If I send simple data (for example a string) through this code, it goes over to server successfully ( through socket). But when I try to break an actual jpeg image into parts and bind it in nsdictionary to make json, it crashes with the following error.

terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid type in JSON write (NSConcreteData)'. Any help here would be highly appreciated.

EDIT: As explained by bobnoble, I understand the reason for the exception. In that case however, how do I accomplish sending over data to server


Solution

  • Deleting all but the key portions that need to be changed.
    As I stated in the comments the data needs to be in a format JSON handles, raw bytes are not acceptable so one way is to encode the data with Base64. The receiver will also need to decode the Base64 string into data.

    while (b) {
        //get chunk from and dtLength
    
        NSData *imageData = [dt subdataWithRange:NSMakeRange(from, dtLength)];
        NSData *imageBase64Data = [imageData base64EncodedDataWithOptions:0];
        NSString *imageBase64String = [[NSString alloc] initWithData:imageBase64Data encoding: NSUTF8StringEncoding];
    
        // update len and from
    
        NSLog(@"sending imageData =%@. dtLength =%i len =%lli", imageBase64String, dtLength, len);   
    
        // Create projectDictionary3 and add items
    
        // Added image data)
        if(imageData.length) {
            [projectDictionary3 setObject: imageBase64String forKey:@"FData"];
        }
        [projectDictionary3 setObject:@(imageBase64String.length) forKey:@"DataLength"];
    
        // serialize projectDictionary3 into JSON and sent to server];
    }