UIImage Not being Set from NSData - iphone

The goal is to pull a image stored as a varbinary in a sql server through a web service that sends a sqlbinary as a JSON to an iphone. I'm having trouble setting the UIImage from the base64binary sent from the JSON. I'm able to convert the binary to NSData but the image is not being set through the data.
for (int i = 0; i < array.count; i++) {
NSDictionary *mealInfo = [array objectAtIndex:i];
Meal *meal =[[Meal alloc]initWithRestaurant:[mealInfo objectForKey:#"restaurantname"]
mealName:[mealInfo objectForKey:#"itemname"]
description:[mealInfo objectForKey:#"itemdescription"]
Time:[mealInfo objectForKey:#"mealTime"]
price:[mealInfo objectForKey:#"itemprice"]];
//NSString *str = #"data:image/jpg;base64,";
//str = [str stringByAppendingString:[mealInfo objectForKey:#"itemImage"]];
//NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:str]];
NSString *str = [mealInfo objectForKey:#"itemImage"];
NSLog(#"%#", str);
NSData *d = [[NSData alloc]initWithData:[NSData dataFromBase64String:str]];
UIImage *image = [UIImage imageWithData:d];
[meal setMealImage:image];
[meals addObject:meal];
}
NSLog(#"%#",[[meals objectAtIndex:0]mealPrice]);
NSLog(#"This is how many meals %d", meals.count);

Assuming the string containing the base 64 encoded is good, your code looks OK. I would look at the dataFromBase64String method to see if that is causing the problem. Here is a version I use based on some else's work:
-(NSData *)dataFromBase64EncodedString:(NSString *)string{
if (string.length > 0) {
//the iPhone has base 64 decoding built in but not obviously. The trick is to
//create a data url that's base 64 encoded and ask an NSData to load it.
NSString *data64URLString = [NSString stringWithFormat:#"data:;base64,%#", string];
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:data64URLString]];
return data;
}
return nil;
}
You could add a NSData category with this method to make its use very convenient.

Related

Saving in NSDocumentDirectory uniquely

Hi Im really having a hard time saving in my NSDocumentDirectory.Im using AGImagePickerby the way. Yes I was able to save this in NSDocumentDirectory. But how to save them uniquely ( in terms of their own then converting their names into oneSlotImages) or save them with their unique IDs then load them back. Sorry Im kinda new to this UIImagePickerControllerMediaURL thing., I think that would be my solution to my other problem for not overlaping them when saving. How to save this using their unique ID, or UIImagePickerControllerMediaURL.
for (int i = 0; i < info.count; i++) {
NSLog(#"%#", [info objectAtIndex:i]);
NSArray *paths = NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask ,YES );
NSString *documentsDir = [paths objectAtIndex:0];
NSString *savedImagePath = [documentsDir stringByAppendingPathComponent:[NSString stringWithFormat:#"oneSlotImages%d.png", i]];
ALAssetRepresentation *rep = [[info objectAtIndex: i] defaultRepresentation];
UIImage *image = [UIImage imageWithCGImage:[rep fullResolutionImage]];
//----resize the images
image = [self imageByScalingAndCroppingForSize:image toSize:CGSizeMake(256,256*image.size.height/image.size.width)];
NSData *imageData = UIImagePNGRepresentation(image);
[imageData writeToFile:savedImagePath atomically:YES];
Thanks for the help. Much Appreciated.
You could always keep a list of used names and do something like this
int i = 1;
while([listOfUsedNames containsObject:nextAvailableTile]) {
nextAvailableTitle = [kDefaultImageName stringByAppendingFormat:#" %d", i];
i++;
}
// found an unused name
The URL for each image is unique right? So we can make use of this. Convert the URL into MD5 string (which form a unique identifier for each image). And save with that name (like "MD5string.png").
Why can't we use this?
Hope this helps you.
For converting to MD5, please create a file named NSString+MD5.h and put the code
#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonDigest.h>
#interface NSString(MD5)
- (NSString *)MD5;
#end
in it.
Then in the NSString+MD5.m,
#import "NSString+MD5.h"
#implementation NSString(MD5)
- (NSString*)MD5
{
const char *ptr = [self UTF8String];
unsigned char md5Buffer[CC_MD5_DIGEST_LENGTH];
CC_MD5(ptr, strlen(ptr), md5Buffer);
NSMutableString *output = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
for(int i = 0; i < CC_MD5_DIGEST_LENGTH; i++)
[output appendFormat:#"%02x",md5Buffer[i]];
return output;
}
#end
Import the NSString+MD5.h class where ever you want to use the MD5 function with normal NSString object.
In you code if you have the UIImagePickerControllerMediaURL string, since it is unique for every file you can convert in to MD5 String like
NSString *imgURL = [NSString stringWithString: UIImagePickerControllerMediaURL];
NSString *MD5String = [imgURL MD5];
NSString *savedImagePath = [documentsDir stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.png", MD5String]];
Use that path to save your image file.
On Loading,
Convert the UIImagePickerControllerMediaURL into MD5 and check in the Documents directory for the file
// In this the UIImagePickerControllerMediaURL is the URL of media file to load
NSString *imgURL = [NSString stringWithString: UIImagePickerControllerMediaURL];
NSString *MD5String = [imgURL MD5];
NSString *savedImagePath = [documentsDir stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.png", MD5String]];
Then do the checking with the fileExistsAtPath method of NSFileManager and if exists then load the file from the path. Thats it.
Note: For this you want to keep the UIImagePickerControllerMediaURL of the images you saved in documents directory locally somewhere in your app (In DB or NSUserDefaults) for make use of then at the time of loading.
Try this:
NSMutableString *imageName = [[[NSMutableString alloc] initWithCapacity:0] autorelease];
CFUUIDRef theUUID = CFUUIDCreate(kCFAllocatorDefault);
if (theUUID) {
[imageName appendString:NSMakeCollectable(CFUUIDCreateString(kCFAllocatorDefault, theUUID))];
CFRelease(theUUID);
}
[imageName appendString:#".png"];

iOS zip with gzipDeflate

I'm using the NSData+compression.h and the Base64Transcoder.h elements to be able to zip and unzip content.
Basically to unzip the server responses.
The unzip method works perfectly
+ (NSString *) unzip: (NSString*) stringValue{
Byte inputData[[stringValue lengthOfBytesUsingEncoding:NSUTF8StringEncoding]];
[[stringValue dataUsingEncoding:NSUTF8StringEncoding] getBytes:inputData];
size_t inputDataSize = (size_t)[stringValue length];
size_t outputDataSize = EstimateBas64DecodedDataSize(inputDataSize);
Byte outputData[outputDataSize];//prepare a Byte[] for the decoded data
Base64DecodeData(inputData, inputDataSize, outputData, &outputDataSize);
NSData *theData = [[NSData alloc] initWithBytes:outputData length:outputDataSize];
//And now we gunzip:
NSData* result = [theData gzipInflate];//make bigger==gunzip
NSString *temp = [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
return temp;
}
But when I try to zip a content, using the simetric way, the gzipDeflate fails, and return an empty or nil value.
This is my zip code
+ (NSData *) zip:(NSData *) theSourceData {
// And now we zip:
NSData *result = [theSourceData gzipDeflate];
Byte inputData[[result length]];
[result getBytes:inputData];
size_t inputDataSize = (size_t)[result length];
size_t outputDataSize = EstimateBas64DecodedDataSize(inputDataSize);
char outputData[outputDataSize];//prepare a Byte[] for the decoded data
Base64EncodeData(inputData, inputDataSize, outputData, &outputDataSize, NO);
NSData *theData = [[NSData alloc] initWithBytes:outputData length:outputDataSize];
return theData;
}
Any suggestions?
Thanks
The problem was on the Base64 encoder.
+ (NSString *) zip:(NSData *) theSourceData {
// And now we zip:
NSData *result = [theSourceData gzipDeflate];
NSString *source = [NSString base64StringFromData:result length:[result length]];
return source;
}
We've integrated the base64StringFromData:length: method to solve it.
Thanks,
Ivan

how to encode a UInt32 scalar type into a NSData object

I am currently creating this NSData object. I would like to put in sever different objects that are of type NSString and UInt32. I know how to put a NSString into my NSData object, but I don't know how to do this with a UInt32 scalar type.
this is how I do it with a NSString
- (void) constructRequest
{
NSString *mystring = [[NSString alloc] initWithString:[self addMethodName]];
UInt32 protocolInt = [self addProtocolVersion];
NSData* data=[mystring dataUsingEncoding:NSUTF8StringEncoding];
[data writeToFile:#"/Users/imac/Desktop/_dataDump.dat" atomically:YES];
}
So I have figured it out, and instead of just updating my question I will put in the answer so others can see that this question has been answered if they are looking to do something similar.
code is as follows
- (void) constructRequest
{
//NSString *mystring = [[NSString alloc] initWithString:[self addMethodName]];
UInt32 protocolInt = [self addProt];
NSData * data = [[NSData alloc] initWithBytes:&protocolInt length:sizeof(protocolInt)];
//NSData* data=[mystring dataUsingEncoding:NSUTF8StringEncoding];
[data writeToFile:#"/Users/imac/Desktop/_dataDump.dat" atomically:YES];
}
Does it need to be NSData? You could use NSString or NSNumber (both can be saved in a property list).
Your scheme doesn't really distinguish between a 4-byte string and a UInt32, if that matters.
You can use htonl(),htons(), ntohl() and ntohs() to make it endian-safe.
htonl()--"Host to Network Long int" 32Bytes
ntohl()--"Network to Host Long int" 32Bytes
htons()--"Host to Network Short int" 16Bytes
ntohs()--"Network to Host Short int" 16Bytes
Example:
- (void)testExample {
UInt32 length = 0x1a2b3c4d;
NSLog(#"%x", length);
length = htonl(length);
NSLog(#"%x", length);
NSMutableData *data = [[NSMutableData alloc] init];
[data appendBytes:&length length:4];
NSLog(#"%#", data);
}
print:
2015-10-29 15:46:49.224 UPHTTP-iOS[3896:101301] 1a2b3c4d
2015-10-29 15:46:49.224 UPHTTP-iOS[3896:101301] 4d3c2b1a
2015-10-29 15:46:49.224 UPHTTP-iOS[3896:101301] <1a2b3c4d>

NSString to NSData conversion Problem

I have some Bytes of image in my string and i want to draw it to UIImageView ...Here is my code
NSString* str= #"<89504e47 0d0a1a0a 0000000d 49484452 ........... 454e44ae 426082>";
NSData* data=[str dataUsingEncoding:NSUTF8StringEncoding];
NSLog(#"My NSDATA %#",data);
imageView.image=[UIImage imageWithData:data];
Now when i saw that printed data on console it is not in same format what i gave to that string..The output is something like.....
<3c383935 30346534 37203064 30613161..........
So my imageview show nothing..... please help
if question was: How to convert string data to image then this is answer.
NSData *imgData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"icon" ofType:#"png"]];
// set your string data into inputString var
NSString *inputString = [imgData description];
NSLog(#"input string %#",inputString);
// clearing string from trashes
NSString *dataStr = [inputString stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#"<>"]];
// separate by words of 4 bytes
NSArray *words = [dataStr componentsSeparatedByString:#" "];
// calculate number of bytes
NSArray *sizes = [words valueForKey:#"length"];
int sizeOfBytes = 0;
for (NSNumber *size in sizes) {
sizeOfBytes += [size intValue]/2;
}
int bytes[sizeOfBytes];
int counts = 0;
for (NSString *word in words) {
// convert each word from string to int
NSMutableString *ostr = [NSMutableString stringWithCapacity:[word length]];
while ([word length] > 0) {
[ostr appendFormat:#"%#", [word substringFromIndex:[word length] - 2]];
word = [word substringToIndex:[word length] - 2];
}
NSScanner *scaner = [NSScanner scannerWithString:ostr];
unsigned int val;
[scaner scanHexInt:&val];
bytes[counts] = val;
counts++;
}
// get NSData form c array
NSData* data = [NSData dataWithBytes:bytes length:sizeOfBytes];
NSLog(#"My NSDATA %#",data);
// your image is ready
UIImage *image = [UIImage imageWithData:data];
NSLog(#"image: %#",image);
what you are seeing in NSLog output are the ASCII codes of the string characters.
for example:
NSString* str = #"A";
NSData* data=[str dataUsingEncoding:NSUTF8StringEncoding];
NSLog(#"%#",data);
you will see something like:
<41....
that's because 0x41 is the code for letter A.
Same is happening with your string.
The data is exactly what you're feeding it: a simple string (printed as raw byte values). But I guess your input string is a hexdump and you manually need to turn into bytes.

NSData to NString conversion problem

I'm getting an HTML file as NSData and need to extract some parts of it. For that I need to convert it to NSString with UTF8 encoding. The thing is that this conversion fails, probably because the NSData contains bytes that are invalid for UTF8. I have tried to get the byte array of the data and go over it, but each time I come across non ASCII character (hebrew letters for example) I get jibrish.
Help will be appreciated.
UPDATE:
To Gordon - the NSData generated like that:
NSData *theData = [NSURLConnection sendSynchronousRequest:theRequest returningResponse:&theResponse error:&theError];
When I say that the conversion fails I mean that
[[NSString alloc] initWithData:temp encoding:NSUTF8StringEncoding]
returns nil
To Ed - Here is my code (I got the Byte array from NSData, found what I need, and constructed another Byte array from that - turned it to NSData and then attempted to convert it to NSString... sounds kinda complicated...)
-(NSString *)UTF8StringFromData:(NSData *)theData{
Byte *arr = [theData bytes];
NSUInteger begin1 = [self findIndexOf:#"<li>" bArr:arr size:[theData length]]+4;
NSUInteger end1 = [self findIndexOf:#"</li></ol>" bArr:arr size:[theData length]];
Byte *arr1 = (Byte *)malloc(sizeof(Byte)*((end1-begin1+1)));
NSLog(#"%d %d",begin1, end1);
int j = 0;
for (int i = begin1; i < end1; i++){
arr1[j] = arr[i];
j++;
}
arr1[j]='\0';
NSData *temp = [NSData dataWithBytes:arr1 length:j];
return [[NSString alloc] initWithData:temp encoding:NSUTF8StringEncoding];
}
I know this is an old topic but it came up when I was looking for the solution today. I've solved it now so I'm just posting it for others who might run into this page looking for a solution.
Here's what I do in an asynchronous request:
I first store the text encoding name in connection:didReceiveResponse using
encodingName = [[NSString alloc] initWithString:[response textEncodingName]];
Then later in my connectionDidFinishLoading method I used
NSStringEncoding encoding = CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding((CFStringRef) encodingName));
NSString *payloadAsString = [[NSString alloc] initWithData:receivedData encoding:encoding];
To Gordon - the NSData generated like that:
NSData *theData = [NSURLConnection sendSynchronousRequest:theRequest returningResponse:&theResponse error:&theError];
When I say that the conversion fails I mean that
[[NSString alloc] initWithData:temp encoding:NSUTF8StringEncoding]
returns nil
To Ed - Here is my code (I got the Byte array from NSData, found what I need, and constructed another Byte array from that - turned it to NSData and then attempted to convert it to NSString... sounds kinda complicated...)
-(NSString *)UTF8StringFromData:(NSData *)theData{
Byte *arr = [theData bytes];
NSUInteger begin1 = [self findIndexOf:#"<li>" bArr:arr size:[theData length]]+4;
NSUInteger end1 = [self findIndexOf:#"</li></ol>" bArr:arr size:[theData length]];
Byte *arr1 = (Byte *)malloc(sizeof(Byte)*((end1-begin1+1)));
NSLog(#"%d %d",begin1, end1);
int j = 0;
for (int i = begin1; i < end1; i++){
arr1[j] = arr[i];
j++;
}
arr1[j]='\0';
NSData *temp = [NSData dataWithBytes:arr1 length:j];
return [[NSString alloc] initWithData:temp encoding:NSUTF8StringEncoding];
}
have you checked the charset= in the HTTP headers and/or the document itself? The most likely reason for the conversion to fail is because the bytes don't represent a valid UTF-8 string.
I'm not sure if you're aware, you don't really need to copy the array to another array before putting it into the new NSData object.
-(NSString *)UTF8StringFromData:(NSData *)theData {
Byte *arr = [theData bytes];
NSUInteger begin1 = [self findIndexOf:#"<li>" bArr:arr size:[theData length]]+4;
NSUInteger end1 = [self findIndexOf:#"</li></ol>" bArr:arr size:[theData length]];
Byte *arr1 = arr + begin1;
NSData *temp = [NSData dataWithBytes:arr1 length:end1 - begin1];
return [[NSString alloc] initWithData:temp encoding:NSUTF8StringEncoding];
}
As for your particular problem, I would try looking through the data manually using the debugger. Put a breakpoint after you have your array (arr1). When you hit it, open up the GDB console and try this:
print (char *)arr1
With your code, it should print out the string you're trying to get. (With the code I gave above, it won't stop after the . It'll just keep going).
If the result is not what you expect, then there's something wrong with the data, or perhaps with your begin1 and end1 boundaries.