I am trying to receive a jpeg image from my c# server. The weird thing is when I run it with the debugger and have a break point anywhere in the method it works perfectly fine. Without a breakpoint then I get this error
Corrupt JPEG data: premature end of data segment
Here is my code
(void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {
NSMutableData *data;
data = [NSMutableData new];
switch(eventCode) {
case NSStreamEventHasBytesAvailable:
{
uint8_t buffer[1024];
int len;
while([inputStream hasBytesAvailable]) {
len = [inputStream read:buffer maxLength:sizeof(buffer)];
if (len > 0)
{
[data appendBytes:(const void*)buffer length:sizeof(buffer)];
}
}
UIImage *images = [[UIImage alloc]initWithData:data];
[dvdCover setImage:images];
} break;
case NSStreamEventEndEncountered:
{
//UIImage *images = [[UIImage alloc]initWithData:data];
//[dvdCover setImage:images];
} break;
}
}
hi you can check this code hop it will help you...
case NSStreamEventHasBytesAvailable:
{
uint32_t max_size = 1000000; // Max size of the received imaged you can modify it as your reqirement.
NSMutableData* buffer = [[NSMutableData alloc] initWithLength: max_size];
NSInteger totalBytesRead = 0;
NSInteger bytesRead = [(NSInputStream *)stream read: [buffer mutableBytes] maxLength: max_size];
if (bytesRead != 0) {
while (bytesRead > 0 && totalBytesRead + bytesRead < max_size) {
totalBytesRead+= bytesRead;
bytesRead = [(NSInputStream *)stream read: [buffer mutableBytes] + totalBytesRead maxLength: max_size - totalBytesRead];
}
if (bytesRead >= 0) {
totalBytesRead += bytesRead;
}
else {
// read failure, report error and bail (not forgetting to release buffer)
}
[buffer setLength: totalBytesRead];
yourImageName.image = [UIImage imageWithData: buffer];
[buffer release];
} break;
It seems you are assuming the whole JPEG image will be transferred in one chunk, and you can just read it with one occurence of 'HasBytesAvailable' event. However you should also consider the case where the JPEG image is transferred to you in multiple chunks.
It might work for you if you set breakpoint, because your code execution might be halted somewhere, and your network buffer had plenty time to receive all bytes of the image. But without breakpoints it might not have time to do so.
Try refactoring your code to accumulate the bytes chunk, and only assume it's done when all bytes have been transferred. (Normally you have to know beforehand how many bytes the image is going to be -- or you can just capture the end of stream event)
Related
I am trying to send large sized images from the server to client using the write method of the NSOuptutStream. However I find that after writing 684032 bytes, no more bytes are getting written by the stream. I find this particularly strange. I am able to send images of size < 680432 and receive them properly at the client side. Attached code snippet below. It would be great if someone can point out where exactly I am going wrong.
UIImage *img;
img = [UIImage imageWithContentsOfFile:path];
NSMutableData *imgData = [UIImageJPEGRepresentation(img, 1.0) mutableCopy];
const void *bytes = [imgData mutableBytes];
NSInteger length = [imgData length];
self.bufferLimit = length;
NSLog(#"self.bufferoffset %d self.bufferlimit %d", self.bufferOffset, self.bufferLimit);
uint8_t *crypto_data = (uint8_t *)bytes;
NSInteger bytesWritten;
if([self.outputStream hasSpaceAvailable]) {
NSLog(#"Space Available");
} else NSLog(#"Space Not Available");
while (self.bufferOffset < self.bufferLimit) {
bytesWritten = [self.outputStream write:(uint8_t *)crypto_data maxLength:1024];
NSLog(#"server: bytes weritten %d",bytesWritten);
assert(bytesWritten != 0);
if (bytesWritten == -1) {
[self stopSendWithStatus:#"output buffer write error"];
} else {
self.bufferOffset += bytesWritten;
}
NSLog(#"self.bufferoffset %d self.bufferlimit %d", self.bufferOffset, self.bufferLimit);
}
NSLog(#"Done sending");
[self.outputStream close];
When my code hangs this is the output I am left with
...
2012-07-04 13:53:20.903 BasicClientServer[1707:f803] self.bufferoffset 681984 self.bufferlimit 1334301
2012-07-04 13:53:20.903 BasicClientServer[1707:f803] server: bytes weritten 1024
2012-07-04 13:53:20.904 BasicClientServer[1707:f803] self.bufferoffset 683008 self.bufferlimit 1334301
2012-07-04 13:53:20.905 BasicClientServer[1707:f803] server: bytes weritten 1024
2012-07-04 13:53:20.906 BasicClientServer[1707:f803] self.bufferoffset 684032 self.bufferlimit 1334301
and doesnt go beyond this point
I'm programming a client on the iPhone. I want to send some strings, and receive an image from the server.
I found this tutorial (http://www.devx.com/wireless/Article/43551), it has been very useful. It works if I want to receive strings, but now I want to receive an image, and I can't make it work.
This is my code when the iPhone receives data. It's a mix made with the tutorial and this answer from JeremyP (http://stackoverflow.com/questions/4613218):
- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {
switch(eventCode) {
case NSStreamEventHasBytesAvailable: {
if (data == nil) {
data = [[NSMutableData alloc] init];
}
uint8_t buf[102400];
unsigned int len = 0;
len = [(NSInputStream *)stream read:buf maxLength:102400];
if(len) {
[data appendBytes:(const void *)buf length:len];
// Recibir img
uint8_t size; // Let's make sure size is an explicit width.
NSInteger totalBytesRead = 0;
NSInteger bytesRead = [iStream read: &size maxLength: sizeof size];
while (bytesRead > 0 && totalBytesRead + bytesRead < sizeof size) {
totalBytesRead+= bytesRead;
bytesRead = [iStream read: &size + totalBytesRead maxLength: (sizeof size) - totalBytesRead];
}
if (bytesRead >= 0) {
totalBytesRead += bytesRead;
}
else {
// read failure, report error and bail
}
if (totalBytesRead < sizeof size) {
// connection closed before we got the whole size, report and bail
}
size = ntohl(size); // assume wire protocol uses network byte ordering
NSMutableData* buffer = [[NSMutableData alloc] initWithLength: size];
totalBytesRead = 0;
bytesRead = [iStream read: [buffer mutableBytes] maxLength: size];
while (bytesRead > 0 && totalBytesRead + bytesRead < size) {
totalBytesRead+= bytesRead;
bytesRead = [iStream read: [buffer mutableBytes] + totalBytesRead maxLength: size - totalBytesRead];
}
if (bytesRead >= 0) {
totalBytesRead += bytesRead;
}
else {
// read failure, report error and bail (not forgetting to release buffer)
}
if (totalBytesRead < size) {
// connection closed before we got the whole image, report and bail (not forgetting to release buffer)
}
else {
[buffer setLength: size];
}
imgResultado.image = [UIImage imageWithData: buffer];
[buffer release];
[data release];
data = nil;
}
else {
NSLog(#"No data.");
}
} break;
}}
It doesn't work... could you help me?
Well, I made it work this way, but I'm no sure if there's a better way.
- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {
switch(eventCode) {
case NSStreamEventHasBytesAvailable:
{
uint32_t max_size = 1000000; // Max size of the received imaged.
NSMutableData* buffer = [[NSMutableData alloc] initWithLength: max_size];
NSInteger totalBytesRead = 0;
NSInteger bytesRead = [(NSInputStream *)stream read: [buffer mutableBytes] maxLength: max_size];
if (bytesRead != 0) {
while (bytesRead > 0 && totalBytesRead + bytesRead < max_size) {
totalBytesRead+= bytesRead;
bytesRead = [(NSInputStream *)stream read: [buffer mutableBytes] + totalBytesRead maxLength: max_size - totalBytesRead];
}
if (bytesRead >= 0) {
totalBytesRead += bytesRead;
}
else {
// read failure, report error and bail (not forgetting to release buffer)
}
[buffer setLength: totalBytesRead];
imgResultado.image = [UIImage imageWithData: buffer];
[buffer release];
}
} break;
}}
With this method, the received image must be smaller than max_size.
If you know a better way to do this, please let me know! ;)
If all you want to do is download an image from the server to display, take a look at this:
https://github.com/michaelkamprath/iPhoneMK/tree/master/Views/MKNetworkImageView
There are a lot of built in functions to the iOS that will handle image downloading for you. That is, if you can encapsulate the entities you want to download as separate URLs (e.g., a web server).
If, however, you are trying to send and receive data across the same TCP connection, I would strongly advise that you change to a more RESTful approach. Partly because it is easier to implement from the client side, partly because you don't have to worry (as much) about the underlying TCP connection.
So I'm making an iOS app that constantly sends and array of points through NSStreams, but because sometimes the sender writes two arrays before the receiver receives one, I decided to first write the length, then the array data itself, so that the receiver knows how many bytes to process.
sender:
if (_outStream && [_outStream hasSpaceAvailable]){
const uint8_t *buffer = [data bytes];
uint64_t length = CFSwapInt64HostToLittle([data length]);
NSLog(#"Sending bytes with length: %llu", length);
int er1 = [_outStream write:(const uint8_t *)&length maxLength:sizeof(length)];
int er2 = [_outStream write:buffer maxLength:length];
if (er1 < 0 || er2 < 0) {
[self _showAlert:#"Failed sending data to peer"];
}
}
receiver:
case NSStreamEventHasBytesAvailable:
{
if (stream == _inStream) {
uint8_t *b;
int len = 0;
len = [_inStream read:b maxLength:8];
uint64_t dataLength = CFSwapInt64LittleToHost(*b);
NSLog(#"Received bytes with length: %llu", dataLength);
if(len < 0) {
if ([stream streamStatus] != NSStreamStatusAtEnd)
[self _showAlert:#"Failed reading data from peer"];
} else if (len > 0){
uint8_t bytes[dataLength];
int length = [_inStream read:bytes maxLength:dataLength];
[currentDownload appendBytes:bytes length:length];
id pointsArray = [NSKeyedUnarchiver unarchiveObjectWithData:currentDownload];
[currentDownload release];
currentDownload = [[NSMutableData alloc] init];
if ([pointsArray isKindOfClass:[NSArray class]]) {
[drawScene addNewPoint:[[pointsArray objectAtIndex:0] CGPointValue] previousPoint:[[pointsArray objectAtIndex:1] CGPointValue]];
}
}
}
break;
}
The problem is that the receiver receives an incorrect integer, hence it reads an incorrect amount of bytes.
Can anyone help me with this?
Could it be that when you read the data, you're starting with the introductory bits intended to convey length, rather than starting with the actual data?
For:
[currentDownload appendBytes:bytes length:length];
try substituting something like this:
NSRange rangeLeftover = NSMakeRange(sizeof(uint8_t), [currentDownload length] - sizeof(uint8_t));
NSData *dataLeftover = [currentDownload subdataWithRange:rangeLeftover];
uint8_t bytesLeftover[[dataLeftover length]];
[dataLeftover getBytes:&bytesLeftover length:[dataLeftover length]];
currentDownload = [NSMutableData data]; // clear
[currentDownload appendBytes:bytesLeftover length:[dataLeftover length]];
I am making image receiver with iPhone.
The server send image file with byte.
and, i tried to make this bytes to image.
But, i can not make image. already, several days past...
i really need your help...
this is source code that i use.
Byte recvBuffer[500];
memset(recvBuffer, '\0', sizeof(recvBuffer));
[iStream read:recvBuffer maxLength:sizeof(recvBuffer)-1];
NSUInteger len = sizeof(recvBuffer);
NSData *webdata = [NSData dataWithBytes:recvBuffer length:len];
imageview.image = [UIImage imageWithData:webdata];
if you give a comment, i will really appriciate! thank you for reading!
badgerr's answer is substantially the one I would use, but since the question is tagged Objective-C the code should really be in Objective-C - omething like the following. Note that over a TCP/IP connection, -read:maxLength: may return before the requested number of bytes has been read.
uint32_t size; // Let's make sure size is an explicit width.
NSInteger totalBytesRead = 0;
NSInteger bytesRead = [istream read: &size maxLength: sizeof size];
while (bytesRead > 0 && totalBytesRead + bytesRead < sizeof size)
{
totalBytes+= bytesRead;
bytesRead = [istream read: &size + totalBytesRead maxLength: (sizeof size) - totalBytesRead];
}
if (bytesRead >= 0)
{
totalBytesRead += bytesRead;
}
else
{
// read failure, report error and bail
}
if (totalBytesRead < sizeof size)
{
// connection closed before we got the whole size, report and bail
}
size = ntohl(size); // assume wire protocol uses network byte ordering
NSMutableData* buffer = [[NSMutableData alloc] initWithLength: size];
totalBytesRead = 0;
bytesRead = [istream read: [buffer mutableBytes] maxLength: size];
while (bytesRead > 0 && totalBytesRead + bytesRead < size)
{
totalBytes+= bytesRead;
bytesRead = [istream read: (char*)[buffer mutableBytes] + totalBytesRead maxLength: size - totalBytesRead];
}
if (bytesRead >= 0)
{
totalBytesRead += bytesRead;
}
else
{
// read failure, report error and bail (not forgetting to release buffer)
}
if (totalBytesRead < size)
{
// connection closed before we got the whole image, report and bail (not forgetting to release buffer)
}
else
{
[buffer setLength: size];
}
imageView.image = [UIImage imageWithData: buffer];
[buffer release];
I typed the above straight in to SO, so it is not tested or even compiled.
TCP/IP is a protocol which is OS independent, so the fact that you're using XP on the server should not affect anything, aside from potentially using the windows API for socket operations.
Claus Broch is correct in saying that 499 bytes looks a bit small for an image. What I suggest you do instead is first find the total size of the image (in bytes) on the server, then send that value at the beginning of the TCP stream, followed by the image data. On the receiving end, your code should first read this size value, allocate some memory of that size, then read that many bytes into it. You haven't posted your server code, so I can't help with that, but the client could look a little something like:
unsigned int size = 0; //assumes the size is sent as an int
Byte* recvBuffer;
[iStream read:&size maxLength:sizeof(unsigned int)];
recvBuffer = new Byte[size];
memset(recvBuffer, 0, size);
[iStream read:recvBuffer maxLength:size];
NSData *webdata = [NSData dataWithBytes:recvBuffer length:size];
imageview.image = [UIImage imageWithData:webdata];
delete [] recvBuffer;
Edit My inner C++ made me use new and delete. While you can use this in Obj-C using the .mm file suffix, this question is tagged Objective-C. You should use JeremyP's answer, as it also includes error checking and a more reliable way of reading the complete image.
I have a problem with NSInputStream. Here is my code:
case NSStreamEventHasBytesAvailable:
printf("BYTE AVAILABLE\n");
int len = 0;
NSMutableData *data = [[NSMutableData alloc] init];
uint8_t buffer[32768];
if(stream == iStream)
{
printf("Receiving...\n");
len = [iStream read:buffer maxLength:32768];
[data appendBytes:buffer length:len];
}
[iStream close];
I try to read small data and it works perfectly on simulator and real iPhone.
If I try to read large data (more than 4kB or maybe 5kB), the real iPhone just can read 2736 bytes and stop.
Why is it? Help me plz!
Merci d'avance!
Your data object needs to be external to your stream handler. It is often the case that when large abounts of data are coming in, you get it in chunks and not all at once. Just keep appending data to it until you receive bytesRead == 0; Then you can close your stream and use the data.
case NSStreamEventHasBytesAvailable: {
NSInteger bytesRead;
uint8_t buffer[32768];
// Pull some data off the network.
bytesRead = [self._networkStream read:buffer maxLength:sizeof(buffer)];
if (bytesRead == -1) {
[self _stopReceiveWithFailure];
} else if (bytesRead == 0) {
[self _stopReceiveWithSuccess];
} else {
[data appendBytes:buffer length:len];
}
Looks like you're creating a new data object every time... perhaps you should be creating & retaining it as a property, and appending to it as you are above.