I have a jpg image which I am converting to data using the UIImageJPEGRepresentation function
I am then sending the data to a server online and getting it back when it is needed though I get this string:
<ffd8ffe0 00104a46 49460001 01000001 00010000 ffe10058 45786966 00004d4d...>
And I don't know how to convert it back to an image
Thanks in advance
I managed to find a way to do it by converting the string to a base64 string like this:
+ (NSString *) encodeToBase64:(NSData *) rawBytes {
return [StringMethods encodeToBase64:(const uint8_t*) rawBytes.bytes length:rawBytes.length];
}
+ (NSString *) encodeToBase64:(const uint8_t *)input length:(NSInteger) length {
NSMutableData *data = [NSMutableData dataWithLength:((length + 2) / 3) * 4];
uint8_t *output = (uint8_t *)data.mutableBytes;
for (NSInteger i = 0; i < length; i += 3) {
NSInteger value = 0;
for (NSInteger j = i; j < (i + 3); j++) {
value <<= 8;
if (j < length) {
value |= (0xFF & input[j]);
}
}
NSInteger index = (i / 3) * 4;
output[index + 0] = encodingTable[(value >> 18) & 0x3F];
output[index + 1] = encodingTable[(value >> 12) & 0x3F];
output[index + 2] = (i + 1) < length ? encodingTable[(value >> 6) & 0x3F] : '=';
output[index + 3] = (i + 2) < length ? encodingTable[(value >> 0) & 0x3F] : '=';
}
return [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
}
Then I saved it onto the server then when loading back in I used this function:
- (NSData *)base64DataFromString: (NSString *)string {
unsigned long ixtext, lentext;
unsigned char ch, inbuf[4], outbuf[3];
short i, ixinbuf;
Boolean flignore, flendtext = false;
const unsigned char *tempcstring;
NSMutableData *theData;
if (string == nil){
return [NSData data];
}
ixtext = 0;
tempcstring = (const unsigned char *)[string UTF8String];
lentext = [string length];
theData = [NSMutableData dataWithCapacity: lentext];
ixinbuf = 0;
while (true) {
if (ixtext >= lentext) {
break;
}
ch = tempcstring [ixtext++];
flignore = false;
if ((ch >= 'A') && (ch <= 'Z')) {
ch = ch - 'A';
} else if ((ch >= 'a') && (ch <= 'z')) {
ch = ch - 'a' + 26;
} else if ((ch >= '0') && (ch <= '9')) {
ch = ch - '0' + 52;
} else if (ch == '+') {
ch = 62;
} else if (ch == '=') {
flendtext = true;
} else if (ch == '/') {
ch = 63;
} else {
flignore = true;
}
if (!flignore) {
short ctcharsinbuf = 3;
Boolean flbreak = false;
if (flendtext) {
if (ixinbuf == 0) {
break;
}
if ((ixinbuf == 1) || (ixinbuf == 2)) {
ctcharsinbuf = 1;
} else {
ctcharsinbuf = 2;
}
ixinbuf = 3;
flbreak = true;
}
inbuf [ixinbuf++] = ch;
if (ixinbuf == 4) {
ixinbuf = 0;
outbuf[0] = (inbuf[0] << 2) | ((inbuf[1] & 0x30) >> 4);
outbuf[1] = ((inbuf[1] & 0x0F) << 4) | ((inbuf[2] & 0x3C) >> 2);
outbuf[2] = ((inbuf[2] & 0x03) << 6) | (inbuf[3] & 0x3F);
for (i = 0; i < ctcharsinbuf; i++) {
[theData appendBytes: &outbuf[i] length: 1];
}
}
if (flbreak) {
break;
}
}
}
return theData;
}
And finally to convert it into an image I was this simple method:
UIImage *image = [UIImage imageWithData:imageData];
Is what you are showing a string, or is that what you get when you display NSData? I believe that if you log binary data, it comes out as you've shown.
What you have shown is hexadecimal data, not base64, as the other poster suggested.
You could either write code that uses sscanf() to pull out int values from your hex string, or create an NSScanner object and use it's scanHexInt method. If you google "convert hex NSString to integer" you should find both approaches.
Since your values have spaces between them, NSScanner might be your best bet.
Issue
You are sending NSData to server not NSString, and that's why you are getting this NSData on that format read by you as NSString.
Solution
First you need to send it correctly as NSString to server by doing this:
NSData *imageData= UIImagePNGRepresentation(yourImage);
NSString *encodedString = [imageData base64EncodedStringWithOptions:0];
After you send it to NSString, now you get it back an manipulate it like this. I am using NSData Base64 library to perform this task.
You just manually copy these files to your project. Import the classes to your project and these lines to your code:
#import "NSData+Base64.h"
//This function converts your base64string (NSString Class) to NSData
NSData *data = [[NSData alloc] initWithData:[NSData dataFromBase64String:base64String]];
//Here is where you convert it to UIImage
UIImage *image = [UIImage imageWithData:data];
P.S You can also follow your answer, which to me seems correct, but I just wanted to let you know where were you doing wrong.
This seems to be a good answer for converting:
NSData *dataImage = [[NSData alloc] init];
dataImage = UIImagePNGRepresentation(image);
NSString *stringImage = [dataImage base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
which you can find here:NSString to UIImage
Related
I have a simple ROT13 method that encodes or decodes a string.
+ (NSString *)ROT13encodeString:(NSString *)aString {
if (!aString) {
return nil;
}
// Find text between brackets
NSCharacterSet *delimiters = [NSCharacterSet characterSetWithCharactersInString:#"[]"];
NSArray *splitString = [aString componentsSeparatedByCharactersInSet:delimiters];
// ???
NSString *newString;
unsigned length;
unichar *buf;
unsigned i;
length = [aString length];
buf = malloc( (length + 1) * sizeof(unichar) );
[aString getCharacters:buf];
buf[length] = (unichar)0; // not really needed....
for (i = 0; i < length; i++) {
if (buf[i] >= (unichar)'a' && buf[i] <= (unichar) 'z') {
buf[i] += 13;
if (buf[i] > 'z') buf[i] -= 26;
} else if (buf[i] >= (unichar)'A' && buf[i] <= (unichar) 'Z') {
buf[i] += 13;
if (buf[i] > 'Z') buf[i] -= 26;
}
}
newString = [NSString stringWithCharacters:buf length:length];
free(buf);
return newString;
}
However, within the text to encode, there are "safe" words that are placed within brackets []. The words, including the brackets should never be encoded, they always need to be in their non-encoded state.
I figured I could pull out all occururances of the bracketed text, but not sure how it would help:
NSCharacterSet *delimiters = [NSCharacterSet characterSetWithCharactersInString:#"[]"];
NSArray *splitString = [aString componentsSeparatedByCharactersInSet:delimiters];
How could I modify my current method to include this?
I don't code in objective-c, but I think this should be close:
+ (NSString *)ROT13encodeString:(NSString *)aString {
if (!aString) {
return nil;
}
// Find text between brackets
NSCharacterSet *delimiters = [NSCharacterSet characterSetWithCharactersInString:#"[]"];
NSArray *splitString = [aString componentsSeparatedByCharactersInSet:delimiters];
// ???
NSString *newString;
unsigned length;
unichar *buf;
unsigned i;
unsigned level;
length = [aString length];
buf = malloc( (length + 1) * sizeof(unichar) );
[aString getCharacters:buf];
buf[length] = (unichar)0; // not really needed....
level = 0;
for (i = 0; i < length; i++) {
if (buf[i] == (unichar)'[') {
level++;
} else if (buf[i] == (unichar)']') {
level--;
} else if (level==0 && buf[i] >= (unichar)'a' && buf[i] <= (unichar) 'z') {
buf[i] += 13;
if (buf[i] > 'z') buf[i] -= 26;
} else if (level==0 && buf[i] >= (unichar)'A' && buf[i] <= (unichar) 'Z') {
buf[i] += 13;
if (buf[i] > 'Z') buf[i] -= 26;
}
}
newString = [NSString stringWithCharacters:buf length:length];
free(buf);
return newString;
}
i am developing app related to bluetooth my iOS device act as a central and watch act as a peripheral.In order to get some response from the watch i need to give some commands to the watch so that it gives info back i have written the following code
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:
(CBCharacteristic *)characteristic error:(NSError *)error
{
NSString *characteristicUUIDstring = TRANSFER_CHARACTERISTIC_UUID;
CBUUID *characteristicUUID = [CBUUID
UUIDWithString:characteristicUUIDstring];
int comm[6];
comm[0]=0x01;
comm[1]=6;
comm[2]=0x53;
comm[3]=0x00;
comm[4]=0xFFFF;
comm[5]=0xFFFF;
NSMutableArray *arr=[[NSMutableArray alloc]initWithCapacity:4];
for (int i = 0; i < 4; i++) {
NSNumber *number = [NSNumber numberWithFloat:comm[i]];
[arr addObject:number];
}
NSLog(#"mutable arr is %#",arr);
NSString *error1;
NSData *dataarr = [NSPropertyListSerialization dataFromPropertyList:arr
format:NSPropertyListBinaryFormat_v1_0 errorDescription:&error1];
NSUInteger len = [dataarr length];
Byte *byteData = (Byte*)malloc(len);
memcpy(byteData, [dataarr bytes], len);
short crc = (short) 0xFFFF;
for (int j = 0; j < [arr count]; j++)
{
Byte c = arr[j];
for (int i = 7; i >= 0; i--)
{
BOOL c15 = ((crc >> 15 & 1) == 1);
BOOL bit = ((c >> (7 - i) & 1) == 1);
crc <<= 1;
if (c15 ^ bit)
{
crc ^= 0x1021; }
}
}
int crc2 = crc - 0xffff0000;
byteData[0] = (Byte) (crc2 % 256);
byteData[1] = (Byte) (crc2 / 256);
NSLog(#"byte data 1is %hhu",byteData[0]);
NSLog(#"byte data 2is %hhu",byteData[1]);
int com[6];
com[0]=0x01;
com[1]=6;
com[2]=0x53;
com[3]=0x00;
com[4]=byteData[0];
com[5]=byteData[1];
NSMutableArray *sendarr=[[NSMutableArray alloc]initWithCapacity:6];
for (int i = 0; i < 6; i++) {
NSNumber *number = [NSNumber numberWithFloat:comm[i]];
[sendarr addObject:number];
}
NSLog(#"mutable arr is %#",sendarr);
// NSData *data = [NSData datawith:&dataByte length:1];
CBMutableCharacteristic *testCharacteristic =
[[CBMutableCharacteristic alloc] initWithType:characteristicUUID
properties:CBCharacteristicPropertyRead|CBCharacteristicPropertyWrite
value:sendarr
permissions:CBAttributePermissionsReadable|CBAttributePermissionsWriteable];
NSLog(#"Read or Write %# ",testCharacteristic);
[peripheral writeValue:dataarr forCharacteristic:testCharacteristic
type:CBCharacteristicWriteWithResponse];
}
I am trying to store text data as compressed blobs.
[db executeUpdate:#"create table blobTable (a text, b blob)"];
[db executeUpdate:#"insert into blobTable (a, b) values (?, compressMe('random text string'))", #"lord of the rings"];
And then I try to query them using:
FMResultSet *rs = [db executeQuery:#"select uncompressMe(b) as k from blobTable where a = ?", #"lord of the rings"];
Where compressMe and uncompressMe are defined as:
FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:dbPath];
[queue inDatabase:^(FMDatabase *adb) {
[adb makeFunctionNamed:#"compressMe" maximumArguments:1 withBlock:^(sqlite3_context *context, int aargc, sqlite3_value **aargv) {
if (sqlite3_value_type(aargv[0]) == SQLITE_TEXT) {
#autoreleasepool {
const char *c = (const char *)sqlite3_value_text(aargv[0]);
NSString *s = [NSString stringWithUTF8String:c];
NSLog(#"string to compress: %#", s);
NSData *compressedBody = [self gzipDeflate:[s dataUsingEncoding:NSUTF8StringEncoding]];
sqlite3_result_blob(context, (__bridge const void *)(compressedBody), [compressedBody length], nil);
}
}
else {
NSLog(#"Unknown formart for StringStartsWithH (%d) %s:%d", sqlite3_value_type(aargv[0]), __FUNCTION__, __LINE__);
sqlite3_result_null(context);
}
}];
}];
[queue inDatabase:^(FMDatabase *adb) {
[adb makeFunctionNamed:#"uncompressMe" maximumArguments:1 withBlock:^(sqlite3_context *context, int aargc, sqlite3_value **aargv) {
if (sqlite3_value_type(aargv[0]) == SQLITE_BLOB) {
#autoreleasepool {
NSLog(#"inside uncompressMe");
NSUInteger len = sqlite3_value_bytes(aargv[0]);
Byte *byteData = (Byte*)malloc(len);
memcpy(byteData, sqlite3_value_blob(aargv[0]), len);
NSData *data = [[NSData alloc] initWithBytes:byteData length:len];
NSData *deflatedBody = [self gzipInflate:data];
NSString *deflatedString = [[NSString alloc] initWithData:deflatedBody encoding:NSUTF8StringEncoding];
sqlite3_result_text(context, (__bridge const void *)(deflatedString), -1, SQLITE_UTF8);
}
}
else {
NSLog(#"Unknown formart for StringStartsWithH (%d) %s:%d", sqlite3_value_type(aargv[0]), __FUNCTION__, __LINE__);
sqlite3_result_null(context);
}
}];
}];
For the sake of completeness, the zip functions are defined as such:
- (NSData *)gzipInflate:(NSData*)data
{
if ([data length] == 0) return data;
unsigned full_length = [data length];
unsigned half_length = [data length] / 2;
NSMutableData *decompressed = [NSMutableData dataWithLength: full_length + half_length];
BOOL done = NO;
int status;
z_stream strm;
strm.next_in = (Bytef *)[data bytes];
strm.avail_in = [data length];
strm.total_out = 0;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
if (inflateInit2(&strm, (15+32)) != Z_OK) return nil;
while (!done)
{
// Make sure we have enough room and reset the lengths.
if (strm.total_out >= [decompressed length])
[decompressed increaseLengthBy: half_length];
strm.next_out = [decompressed mutableBytes] + strm.total_out;
strm.avail_out = [decompressed length] - strm.total_out;
// Inflate another chunk.
status = inflate (&strm, Z_SYNC_FLUSH);
if (status == Z_STREAM_END) done = YES;
else if (status != Z_OK) break;
}
if (inflateEnd (&strm) != Z_OK) return nil;
// Set real length.
if (done)
{
[decompressed setLength: strm.total_out];
return [NSData dataWithData: decompressed];
}
else return nil;
}
- (NSData *)gzipDeflate:(NSData*)data
{
if ([data length] == 0) return data;
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.total_out = 0;
strm.next_in=(Bytef *)[data bytes];
strm.avail_in = [data length];
// Compresssion Levels:
// Z_NO_COMPRESSION
// Z_BEST_SPEED
// Z_BEST_COMPRESSION
// Z_DEFAULT_COMPRESSION
if (deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, (15+16), 8, Z_DEFAULT_STRATEGY) != Z_OK) return nil;
NSMutableData *compressed = [NSMutableData dataWithLength:16384]; // 16K chunks for expansion
do {
if (strm.total_out >= [compressed length])
[compressed increaseLengthBy: 16384];
strm.next_out = [compressed mutableBytes] + strm.total_out;
strm.avail_out = [compressed length] - strm.total_out;
deflate(&strm, Z_FINISH);
} while (strm.avail_out == 0);
deflateEnd(&strm);
[compressed setLength: strm.total_out];
return [NSData dataWithData:compressed];
}
However, the uncompressMe function doesnt seem to succeed. It fails in the Inflate method, which always returns a nil. Any thoughts what I might be doing wrong? I have checked to make sure that the blob column does get populated.
I feel like issue is from below code:
NSUInteger len = sqlite3_value_bytes(aargv[0]);
Byte *byteData = (Byte*)malloc(len);
memcpy(byteData, sqlite3_value_blob(aargv[0]), len);
NSData *data = [[NSData alloc] initWithBytes:byteData length:len];
Try this to load NSData from database instead of creating byte variable and copying it.
const void *bytes = sqlite3_column_blob(statement, 3);
NSData *data = [[NSData alloc] initWithBytes:bytes length:size];
I need to find the sequence of bytes in my image data. I have next code on java, but I need make the same in obj-c.
Java:
private static int searchInBuffer(byte[] pBuf, int iBufferLen) {
for(int i = 0; i<iBufferLen - 7; i++) {
if (pBuf[i] == 'l' && pBuf[i + 1] == 'i' && pBuf[i + 2] == 'n' && pBuf[i + 3] == 'k')
return (int)pBuf[i + 4];
}
return -1;
}
public static int checkFlagInJpeg(String pFullFileName) {
int iRes = -1;
try {
File f = new File(pFullFileName);
FileInputStream is = new FileInputStream(f);
int iBufferSize = 6 * 1024, iCount = 15;
byte buf[] = new byte[iBufferSize];
while((is.available() > 0) && (iCount >= 0)) {
int iRead = is.read(buf),
iFlag = searchInBuffer(buf, iRead);
if (iFlag > 0) {
iRes = iFlag;
break;
}
iCount--;
}
is.close();
}
}
Obj-C (my version):
UIImage *image = [UIImage imageWithCGImage:[[[self.assets objectAtIndex:indexPath.row] defaultRepresentation] fullScreenImage]];
NSData *imageData = UIImageJPEGRepresentation(image, 1.0f);
NSUInteger length = MIN(6*1024, [imageData length]);
Byte *buffer = (Byte *)malloc(length);
memcpy(buffer, [imageData bytes], length);
for (int i=0; i < length - 1; i++) {
if (buffer[i] == 'l' && buffer[i + 1] == 'i' && buffer[i + 2] == 'n' && buffer[i + 3] == 'k')
NSLog(#"%c", buffer[i + 4]);
}
free(buffer);
I'm still not sure, that I understand all aspects of work with bytes, so I need a help.
UPDATE:
The problem was in getting image data. With help of Martin R. I combine to solutions in one and get next working code:
ALAssetRepresentation *repr = [[self.assets objectAtIndex:indexPath.row] defaultRepresentation];
NSUInteger size = (NSUInteger) repr.size;
NSMutableData *data = [NSMutableData dataWithLength:size];
NSError *error;
[repr getBytes:data.mutableBytes fromOffset:0 length:size error:&error];
NSData *pattern = [#"link" dataUsingEncoding:NSUTF8StringEncoding];
NSRange range = [data rangeOfData:pattern options:0 range:NSMakeRange(0, data.length)];
int iRes = -1;
if (range.location != NSNotFound) {
uint8_t flag;
[data getBytes:&flag range:NSMakeRange(range.location + range.length, 1)];
iRes = flag;
}
NSLog(#"%i", iRes);
It's working perfect! Thank you again!
NSData has a method rangeOfData:... which you can use to find the pattern:
NSData *pattern = [#"link" dataUsingEncoding:NSUTF8StringEncoding];
NSRange range = [imageData rangeOfData:pattern options:0 range:NSMakeRange(0, imageData.length)];
If the pattern was found, get the next byte:
int iRes = -1;
if (range.location != NSNotFound && range.location + range.length < imageData.length) {
uint8_t flag;
[imageData getBytes:&flag range:NSMakeRange(range.location + range.length, 1)];
iRes = flag;
}
I am trying to retrieve Base64 string from iOS UIImagePickerController selected event as follows.
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
//on selected
UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
NSData *imgData = UIImageJPEGRepresentation(image, 1.0);
NSString *imageString = [[NSString alloc] initWithBytes: [imgData bytes] length:[imgData length] encoding:NSUTF8StringEncoding];
//NSLog(#"Image Data: %#", imageString); it returns Nothing except "Image Data: "
[picker dismissModalViewControllerAnimated:YES];
[picker.view removeFromSuperview];
[picker release];
}
+ (NSString*)base64forData:(NSData*)theData {
const uint8_t* input = (const uint8_t*)[theData bytes];
NSInteger length = [theData length];
static char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
NSMutableData* data = [NSMutableData dataWithLength:((length + 2) / 3) * 4];
uint8_t* output = (uint8_t*)data.mutableBytes;
NSInteger i;
for (i=0; i < length; i += 3) {
NSInteger value = 0;
NSInteger j;
for (j = i; j < (i + 3); j++) {
value <<= 8;
if (j < length) {
value |= (0xFF & input[j]);
}
}
NSInteger theIndex = (i / 3) * 4;
output[theIndex + 0] = table[(value >> 18) & 0x3F];
output[theIndex + 1] = table[(value >> 12) & 0x3F];
output[theIndex + 2] = (i + 1) < length ? table[(value >> 6) & 0x3F] : '=';
output[theIndex + 3] = (i + 2) < length ? table[(value >> 0) & 0x3F] : '=';
}
return [[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding] autorelease];
}