iPhone - Corrupt JPEG data for image received over HTTP

11,526

Solution 1

Your HTTP code looks correct. You might want to log the size of the receivedData once it's done loading and compare it to the expected size of the image on the server. If it's the expected size, then maybe the image itself is corrupted on the server.

Solution 2

ASI-HTTP can fix this problem.

NSURL *coverRequestUrl = [NSURL URLWithString:imageStringURL];
ASIHTTPRequest *coverRequest = [[ASIHTTPRequest alloc] initWithURL:coverRequestUrl];
[coverRequest setDelegate:self];
[coverRequest setDidFinishSelector:@selector(imageRecieved:)];

[appDelegate.queue addOperation:coverRequest];
[appDelegate.queue go];

My queue variable in appDelegate is ASINetwork queue object. Because I send asynchronous request, so I use it.

- (void)imageRecieved:(ASIHTTPRequest *)response
{
    UIImage *myImage = [UIImage imageWithData:[response responseData]];
}

Solution 3

I fixed this problem by using an NSMutableDictionary.

NSMutableDictionary *dataDictionary;

In my loadData function, I define my data:

NSMutableData *receivedData = receivedData = [[NSMutableData alloc] init];

Then I load the data into my dictionary where the key is [theConnection description] and the object is my data.

[dataDictionary setObject:receivedData forKey:[theConnection description]];

That way in the delegates, I can look up the correct data object for the connection that is passed to the delegate and save to the right data instance otherwise I end up with the JPEG munging/corruption problem.

In didReceiveData, I put:

//get the object for the connection that has been passed to connectionDidRecieveData and that object will be the data variable for that instance of the connection.
NSMutableData *theReceivedData = [dataDictionary objectForKey:[connection description]];

//then act on that data
[theReceivedData appendData:data];

Similarly, in didReceiveResponse, I put:

NSMutableData *theReceivedData = [dataDictionary objectForKey:[connection description]];
[theReceivedData setLength:0];

And in connectionDidFinishLoading: NSMutableData *theReceivedData = [dataDictionary objectForKey:[connection description]]; img = [[UIImage alloc] initWithData:theReceivedData];

And this seems to work very well. By the way, my code is based on Apple's tutorial for NSUrlConnection with the addition of an NSMutableDictionary to keep track of individual connections. I hope this helps. Let me know if you want me to post my full image handling code.

Share:
11,526
bpapa
Author by

bpapa

iOS engineer

Updated on June 18, 2022

Comments

  • bpapa
    bpapa almost 2 years

    I'm getting an image over HTTP, using NSURLConnection, as follows -

    NSMutableData *receivedData;
    
    - (void)getImage {
        self.receivedData = [[NSMutableData alloc] init];
        NSURLConnection *theConnection = // create connection
    }
    
    - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {    
       [receivedData appendData:data];
    }
    
    -(void)connectionDidFinishLoading:(NSURLConnection *)connection {
       [connection release];
    
       UIImage *theImage = [UIImage imageWithData:receivedData];
    }
    

    Usually it works just fine, but sometimes I'm seeing this get logged - : Corrupt JPEG data: premature end of data segment

    At this point, the image does not completely render. I'll see maybe 75% of it, and then the lower right hand corner is a grey box.

    Any ideas on how to approach fixing this? Am I constructing my image improperly?

  • bpapa
    bpapa almost 15 years
    Thanks, this helped out a lot. By doing this I realized it was my own programming error (I was accidently firing off the request twice).
  • CornPuff
    CornPuff almost 13 years
    I was doing the same thing as bpapa. It seems if you launch 2 different NSURLConnections to the same URL, the end result will be corrupt data.
  • Enzo Tran
    Enzo Tran over 12 years
    I got the exact same problem, and it was indeed from the same cause: 2 connections to the same image.
  • user298261
    user298261 over 11 years
    The error is created because both connections are sharing the same data source. When building applications where specific tasks have to fire concurrently (which you did inadvertently, it seems :) ), you either have to have a unique data source for each connection (One-to-One), or create a semaphore so your mutable data source isn't being serialized with the results of multiple connections at once (race conditions). The end result is the creation of corrupted, or incomplete, data! (Which you experienced).
  • Scott Lieberman
    Scott Lieberman about 11 years
    @bpapa - where exactly in your code were you firing off the request twice? Based on my log output, I think I am doing the same, but don't understand why only certain photos would be getting called twice.
  • bpapa
    bpapa about 11 years
    I don't have access to this code anymore, but I believe it was just me making some weird mistakes as an inexperienced iOS developer back in '09. :)
  • JWKot
    JWKot over 10 years
    I use the same method. Works great. Make sure to alloc and init the data object in the dictionary before you send the request though. Otherwise you will end up with the same mistake