I'm working on creating and storing OpenGL ES1 3D models, and want to include image files to be used as textures, within the same file as the 3D model data. I am having trouble loading the image data in a usable format. I'm using UIImageJPEGRepresentation to convert the image data and store it into an NSData. I then append it to a NSMutableData object, along with all the 3D data, and write it out to a file. The data seems to write and read without error, but I encounter problems when trying use the image data to create a "CGImageRef" which I use to generate the texture data for the 3D model. The image data seems to be in an unrecognized format after it is loaded from the file, because it generates the error "CGContextDrawImage: invalid context 0x0.” when I attempt to create the "CGImageRef". I suspect that the image data is gettin misaligned somehow, causing it to be rejected when attempting to create the "CGImageRef". I appreciate any help. I'm stumped at this point. All of the data sizes and offsets add up and look fine. Saves and loads happen without error. The image data just seems off a bit, but I don't know why.
Here's my code:
//======================================================
- (BOOL)save3DFile: (NSString *)filePath {
// load TEST IMAGE into UIIMAGE
UIImage *image = [UIImage imageNamed:#“testImage.jpg"];
// convert image to JPEG encoded NSDATA
NSData *imageData = UIImageJPEGRepresentation(image,1.0);
// Save length of imageData to global "imDataLen" to use later in “load3DFile”
imDataLen = [imageData length];
// TEST: this works fine for CGImageRef creation in “loadTexture”
// traceView.image=[UIImage imageWithData:[imageData subdataWithRange:NSMakeRange(0, imageDataLen)]];
// [self loadTexture];
// TEST: this also works fine for CGImageRef creation in “loadTexture”
// traceView.image=[UIImage imageWithData:txImData];
// [self loadTexture];
fvoh.fileVersion = FVO_VERSION;
fvoh.obVertDatLen = obVertDatLen;
fvoh.obFaceDatLen = obFaceDatLen;
fvoh.obNormDatLen = obNormDatLen;
fvoh.obTextDatLen = obTextDatLen;
fvoh.obCompCount = obCompCount;
fvoh.obVertCount = obVertCount;
fvoh.obElemCount = obElemCount;
fvoh.obElemSize = obElemSize;
fvoh.obElemType = obElemType;
NSMutableData *obSvData;
obSvData=[NSMutableData dataWithBytes:&fvoh length:(sizeof(fvoh))];
[obSvData appendBytes:obElem length:obFaceDatLen];
[obSvData appendBytes:mvElem length:obVertDatLen];
[obSvData appendBytes:mvNorm length:obNormDatLen];
[obSvData appendBytes:obText length:obTextDatLen];
[obSvData appendBytes:&ds length:(sizeof(ds))];
// next, we append image data, and write all data to a file
// seems to work fine, no errors, at this point
[obSvData appendBytes: imageData length:[imageData length]];
BOOL success=[obSvData writeToFile: filePath atomically:YES];
return success;
}
//======================================================
- (void) load3DFile:(NSString *)filePath {
NSData *fvoData;
NSUInteger offSet,fiLen,fhLen,dsLen;
[[FileList sharedFileList] setCurrFile:(NSString *)filePath];
fvoData=[NSData dataWithContentsOfFile:filePath];
fiLen=[fvoData length];
fhLen=sizeof(fvoh);
dsLen=sizeof(ds);
memcpy(&fvoh,[fvoData bytes],fhLen);offSet=fhLen;
//+++++++++++++++++++++++++++++++
obVertDatLen = fvoh.obVertDatLen;
obFaceDatLen = fvoh.obFaceDatLen;
obNormDatLen = fvoh.obNormDatLen;
obTextDatLen = fvoh.obTextDatLen;
obCompCount = fvoh.obCompCount;
obVertCount = fvoh.obVertCount;
obElemCount = fvoh.obElemCount;
obElemSize = fvoh.obElemSize;
obElemType = fvoh.obElemType;
//+++++++++++++++++++++++++++++++
memcpy(obElem, [fvoData bytes]+offSet,obFaceDatLen);offSet+=obFaceDatLen;
memcpy(mvElem, [fvoData bytes]+offSet,obVertDatLen);offSet+=obVertDatLen;
memcpy(mvNorm, [fvoData bytes]+offSet,obNormDatLen);offSet+=obNormDatLen;
memcpy(obText, [fvoData bytes]+offSet,obTextDatLen);offSet+=obTextDatLen;
memcpy(&ds, [fvoData bytes]+offSet,dsLen);offSet+=dsLen;
// the following seem to read the data into “imageData” just fine, no errors
// NSData *imageData = [fvoData subdataWithRange:NSMakeRange(offSet, imDataLen)];
// NSData *imageData = [fvoData subdataWithRange:NSMakeRange((fiLen-imDataLen), imDataLen)];
// NSData *imageData = [NSData dataWithBytes:[fvoData bytes]+offSet length: imDataLen];
NSData *imageData = [NSData dataWithBytes:[fvoData bytes]+(fiLen-imDataLen) length: imDataLen];
// but the contents of imageData seem to end up in an unexpected format, causing error:
// “CGContextDrawImage: invalid context 0x0.” during CGImageRef creation in “loadTexture”
traceView.image=[UIImage imageWithData:imageData];
[self loadTexture];
}
//======================================================
- (void)loadTexture {
CGImageRef image=[traceView.image].CGImage;
CGContextRef texContext;GLubyte* bytes=nil;GLsizei width,height;
if(image){
width=(GLsizei)CGImageGetWidth(image);
height=(GLsizei)CGImageGetHeight(image);
bytes=(GLubyte*) calloc(width*height*4,sizeof(GLubyte));
texContext=CGBitmapContextCreate(bytes,width,height,8,width*4,CGImageGetColorSpace(image),
kCGImageAlphaPremultipliedLast);
CGContextDrawImage(texContext,CGRectMake(0.0,0.0,(CGFloat)width,(CGFloat)height),image);
CGContextRelease(texContext);
}
if(bytes){
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,width,height,0,GL_RGBA,GL_UNSIGNED_BYTE,bytes);
free(bytes);
}
}
//======================================================
I failed to receive any answers to this question. I finally stumbled across the answer myself. When I execute the save3DFile code, instead of adding the image data to NSMutableData *obSvData, using 'appendBytes' as illustrated below:
[obSvData appendBytes: imageData length:[imageData length]];
I instead use 'appendData' as shown here:
[obSvData appendData: imageData];
where imageData was previously filled with the contents of a UIImage and converted to JPEG format in the process as follows:
NSData *imageData = UIImageJPEGRepresentation(image,1.0);
See the complete code listing above for context. Anyway, the using 'appendData' instead of 'appendBytes' made all the difference, and allowed me to store the image data in the same file along with all the other 3D model data (vertices, indices, normals, et cetera), reloading all that data without problem, and successfully create 3D models with textures from a single file.
I am attempting to load image files as an NSString, but all of them come up nil using this code:
NSString *path = [[NSBundle mainBundle] pathForResource:[NSString stringWithUTF8String:name.data()] ofType:nil];
NSString *da = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
I am able to load many files, but all JPEG and PNG files fail for some reason. I thought it might have something to do with encoding so I switched it to usedEncoding, but it still didn't work.
What am I missing?
EDIT:
I have been making an iOS/Android cross platform OpenGL graphics library in C++. Everything works except texture loading. Any file loading from disk goes through one function that is abstracted between systems. I need the image file in an STL string, so that I can pass it to an image parsing library to get the raw pixel data.
I just think that it's reduculous that the function I have can open any file except images.
If you run your code, passing an NSError instance instead of nil,
NSError *error = nil;
NSString *string = [NSString stringWithContentsOfFile:filePath
encoding:NSUTF8StringEncoding
error:&error];
you will see that stringWithContentsOfFile cannot open the image file, returning nil and the error given is:
Error Domain=NSCocoaErrorDomain Code=261 "The operation couldn’t be completed. (Cocoa error 261.)"...
Cocoa error 261 is NSFileReadInapplicableStringEncodingError which means the encoding of the file is different from the one you are passing (NSUTF8StringEncoding). But I have tried with the other encodings, and none works for PNG files.
You can still achieve what you want by loading the file as a UIImage and then converting the UIImage into a Base64 string.
Since iOS 7, this is easier because you can use the built in method base64EncodedStringWithOptions:
// Load the image and convert it to NSData
UIImage *image = [UIImage imageNamed:#"yourImageName"];
NSData *imageData = UIImagePNGRepresentation(image);
// You can use the equivalent UIImageJPEGRepresentation() for JPEG images
// Convert NSData to a Base64 NSString
NSString *base64ImageString = [imageData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
Previous to iOS 7, you can do the exact same thing but you will have to implement your own Base64 encoding method (Or import any of the many already available, eg. nicklockwood/Base64).
Hi I've got the a Problem with decrypting using MIHCrypto v0.3.2. These are my lines of code:
NSString *encrypted_text = #"BdhFH0sd7e9DExiCd50Ykh4spm2BX126skjJ1o8HHjKsN+J7r9IoI9kbB9AAacEpJsAfyesiJsq5gDBhQtcNbB6l88aSgPrEoVwR9ilzuzVcv1q3J1dxs4uIEMuhzoWT+R8//dD2jDdXPyFsdGWJc10CEizPFKpmy2jWhvU8CVs=";
NSBundle *myBundle = [NSBundle mainBundle];
NSString *privateKeyPath= [myBundle pathForResource:#"rsa_1024_priv" ofType:#"pem"];
NSData *privateKeyData = [[NSFileManager defaultManager] contentsAtPath:privateKeyPath];
MIHRSAPrivateKey *privateKey = [[MIHRSAPrivateKey alloc] initWithData:privateKeyData];
NSError *decryptionError = nil;
// decryption
NSData *encData = [encrypted_text dataUsingEncoding:NSUTF8StringEncoding];
NSData *decryptedEncData = [privateKey decrypt:encData error:&decryptionError];
NSString* decryptedText = [[NSString alloc] initWithData:decryptedEncData encoding:NSUTF8StringEncoding]; // iOS 7+, by iOS Core API
if(decryptionError){
DDLogDebug(#"error: %#",[encryptionError localizedDescription]);
}
DDLogDebug(#"decrypted: %#",decryptedEncData);
The problem is debugged here:
error: OpenSLL internal error! (Code=67522668,Description=error:0406506C:rsa routines:RSA_EAY_PRIVATE_DECRYPT:data greater than mod len)
Do you have any Idea?
I finally found a solution:
Using shorter Blocks of Data!
Background (posted by Hohl - here):
Using RSA with large blocks of data seems to be a common issue. Some
wrappers handle this by splitting the data into smaller blocks and
encrypting every block separately. But since RSA isn't intended to
encrypt large blocks of data this won't be implemented in this wrapper.
(Better combine RSA with something like AES if you need features of
both worlds.)
Trying to save ultra hd image in documents directory from gallery. My app is crashing due to memory pressure. How to save image directly from alasset to documents folder without taking into uiimage.
If you have problems with memory I will suggest you to read this How can I release memory of UIImages no longer used first.
If you will decide that you still need copying without UIImage usage you can try following
ALAsset *result; // do not forget to initialize it
ALAssetRepresentation *rawImage = [result defaultRepresentation];
uint8_t *buffer = malloc( rawImage.size );
[rawImage getBytes:buffer fromOffset:0 length:rawImage.size error:NULL];
NSData *d = [NSData dataWithBytes:buffer length:rawImage.size];
[d writeToFile:#"your_file_path_here" atomically:YES];
free(buffer);
UPDATE:
Following code could be more efficient
long long sizeOfRawDataInBytes = rawImage.size;
NSMutableData* rawData = [[NSMutableData alloc]initWithCapacity:sizeOfRawDataInBytes];
void* bufferPointer = [rawData mutableBytes];
NSError* error=nil;
[rawImage getBytes:bufferPointer fromOffset:0 length:sizeOfRawDataInBytes error:&error];
if (error) {
NSLog(#"Getting bytes failed with error: %#",error);
}
else {
[rawData writeToFile: #"your_file_path_here" atomically:YES];
}
I have a PDF file which I downloaded from a server, sometimes the users uploads a corrupted PDF and I need to check if my application can open such a file or not.
So is there a built-in way I could use to check for the PDF corruption ? If not is there a free lightweight PDF framework that I could use to view or checking the corruption ?
Note: Currently I am opening PDF files on a UIWebView.
I've found the solution using the CoreGraphics PDF drawing APIs.
Thanks for this answer.
NSString *path = [[NSBundle mainBundle] pathForResource:#"A_Corrupted_PDF" ofType:#"pdf"];
NSData *data = [[NSFileManager defaultManager] contentsAtPath:path];
CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data);
CGPDFDocumentRef document = CGPDFDocumentCreateWithProvider(provider);
if (document == nil) {
NSLog(#"The PDF is corrupted");
}
CGDataProviderRelease(provider);
CGPDFDocumentRelease(document);