How to handle multiple images with large size? - image

I have list of selected images from Photos gallery.
The array list contain selected PHAssets from Photos
<PHAsset: 0x131334350> 768AD8BA-FE7A-4EE9-B2CF-4DD4AEBE2AE9/L0/001 mediaType=1/0, sourceType=1, (2448x3264), creationDate=2016-03-11 06:50:09 +0000, location=1, hidden=0, favorite=0 ",
"<PHAsset: 0x131334260> CA962E42-A367-4E8D-85C8-934F8C76FE78/L0/001 mediaType=1/0, sourceType=1, (2448x3264), creationDate=2016-03-11 06:50:08 +0000, location=1, hidden=0, favorite=0 "
Now i want to store this images into Document Directory.For that i am converting PHAssets to original image and store it in array, for that code i did
#property (nonatomic, strong) PHImageRequestOptions *requestOptions;
for (PHAsset *asset in assetArray) {
self.requestOptions = [[PHImageRequestOptions alloc] init];
self.requestOptions.resizeMode = PHImageRequestOptionsResizeModeExact;
self.requestOptions.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
// this one is key
self.requestOptions.synchronous = true;
PHImageManager *manager = [PHImageManager defaultManager];
__block UIImage *ima;
// Do something with the asset
[manager requestImageForAsset:asset
targetSize:PHImageManagerMaximumSize
contentMode:PHImageContentModeDefault
options:self.requestOptions
resultHandler:^void(UIImage *image, NSDictionary *info) {
ima = image;
[Albumimages addObject:ima];
}];
}
But problem is that when i selected multiple images with large size(more than 25) app is crash down. Because when i convert PHAsset to original image by using PHImageManager it uses high memory of device.
Please help me to solve this problem. Provide me if there is any other solution to handle selected PHAssets for storing images in application document directory.

PHImageRequestOptions *option = [PHImageRequestOptions new];
option.synchronous = NO;
let screenSize: CGSize = UIScreen.mainScreen().bounds.size
let targetSize = CGSizeMake(screenSize.width, screenSize.height)
[manager requestImageForAsset:asset
targetSize:target
contentMode:PHImageContentModeAspectFill
options:option resultHandler:^(UIImage *result, NSDictionary *info)
{
//this block will be called synchronously
}];
If you set maximum image size when using more images they could crash but if set target size then handles it.

Handle all images with the data instead of covert into original image.
[manager requestImageDataForAsset:asset
options:self.requestOptions
resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info)
{
// UIImage *image = [UIImage imageWithData:imageData];
[Albumimages addObject:imageData];
}];
After that Write image data at document directory path.

Related

How to draw EPS data on NSView

I'm struggling with the problem to draw an eps file on a NSView.
When I first load the eps file from a file and draw it with drawInRect: the image is displayed correctly. However, the image will not be drawn when I load it from an archive file.
I've prepared a dirty small example that you can copy/paste and try out. Create a new Cocoa App project and add this to the delegate method.
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Just a sample eps file
NSURL *url = [NSURL URLWithString: #"http://embedded.eecs.berkeley.edu/concurrency/latex/figure.eps"];
NSImage *epsImage = [[[NSImage alloc] initWithContentsOfURL: url] autorelease];
// Encode data
NSMutableData *mutableData = [[[NSMutableData alloc] init] autorelease];
NSKeyedArchiver *coder = [[[NSKeyedArchiver alloc] initForWritingWithMutableData: mutableData] autorelease];
[coder encodeObject: epsImage forKey: #"image"];
[coder finishEncoding];
NSString *dataFile = [#"~/Desktop/image.data" stringByExpandingTildeInPath];
[mutableData writeToFile: dataFile atomically: YES];
// Decode data
NSData *data = [NSData dataWithContentsOfFile: dataFile];
NSKeyedUnarchiver *decoder = [[NSKeyedUnarchiver alloc] initForReadingWithData: data];
NSImage *loadedImage = [decoder decodeObjectForKey: #"image"];
// Draw image
NSRect rect;
rect.origin = NSZeroPoint;
rect.size = loadedImage.size;
NSView *view = [[NSApp mainWindow] contentView];
[view lockFocus];
[loadedImage drawInRect: rect fromRect: rect operation: NSCompositeSourceOver fraction: 1.0];
[view unlockFocus];
}
To prove that the first loaded image draws correctly just change the line [loadedImage drawInRect:...] to [epsImage drawInRect:...].
I'm using NSKeyedArchiver and NSKeyedUnarchiver here for simulating encodeWithCoder: and initWithCoder:. So please focus on the fact that NSImage with NSEPSImageRep representation, which does not contain a preview (from a resource fork?) and loaded purely as eps commands, is not drawn on a NSView correctly.
Any help is appreciated.
Due to the way that cacheing works on NSImage, I've often found it more effective to actually grab the NSImageRep if I know what the type is.
In our code, we found that the most reliable way to save off images is in their original format, but that requires either saving off the data in its original format somewhere else, or requesting the data from the NSImageRep. Unfortunately, there's not a generic -(NSData*)data method of NSImageRep, so we ended up specifically checking for various types of NSImageRep and saving them off depending on what we knew them to be.
Fortunately, loading is simple, as NSImage::initWithData: will figure out the type based on the data.
Here's our long-standing code for doing this. Basically, it prefers PDF then EPS then it makes a TIFF of anything it doesn't understand.
+ (NSData*) dataWithImage:(NSImage*)image kindString:( NSString**)kindStringPtr
{
if (!image)
return nil;
NSData *pdfData=nil, *newData=nil, *epsData=nil, *imageData=nil;;
NSString *kindString=nil;
NSArray *reps = [image representations];
for (NSImageRep *rep in reps) {
if ([rep isKindOfClass: [NSPDFImageRep class]]) {
// we have a PDF, so save that
pdfData = [(NSPDFImageRep*)rep PDFRepresentation];
PDFDocument *doc = [[PDFDocument alloc] initWithData:pdfData];
newData = [doc dataRepresentation];
if (newData && ([newData length]<[pdfData length])) {
pdfData = newData;
}
break;
}
if ([rep isKindOfClass: [NSEPSImageRep class]]) {
epsData = [(NSEPSImageRep*)rep EPSRepresentation];
break;
}
}
if (pdfData) {
imageData=pdfData;
kindString= #"pdfImage";
} else if (epsData) {
imageData=epsData;
kindString=#"epsImage";
} else {
// make a big copy
NSBitmapImageRep *rep0 = [reps objectAtIndex:0];
if ([rep0 isKindOfClass: [NSBitmapImageRep class]]) {
[image setSize: NSMakeSize( [rep0 pixelsWide], [rep0 pixelsHigh])];
}
imageData = [image TIFFRepresentation];
kindString=#"tiffImage";
}
if (kindStringPtr)
*kindStringPtr=kindString;
return imageData;
}
Once we have the NSData*, it can be saved in a keyed archive, written to disk or whatever.
On the way back in, load in the NSData* and then
NSImage *image = [[NSImage alloc] initWithData: savedData];
and you should be all set.

Storing a PDF generated 'on the fly' for iPad on IOS6.1

I am trying to create a PDF report from an iPad app using xcode 4.6. I know a valid pdf file is being created when run on the simulator, because I can dig it out and preview it. The commented out code does this. The problem is that I can't write it somewhere I can get at it on the iPad.
I've tried using UIGraphicsBeginPDFContextToData instead and trying to write the image out to the PhotoAlbum instead. The problem here is that when I convert the NSMutableData into an image it returns nil.
Here is the code. Thanks for any help you can give me.
- (IBAction)makePDF:(UIButton *)sender
{
CFAttributedStringRef currentText = CFAttributedStringCreate(NULL, (CFStringRef)self.labelCopyright.text, NULL);
if (currentText)
{
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(currentText);
if (framesetter)
{
// NSString *rootPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, //NSUserDomainMask, YES) objectAtIndex:0];
// NSString *pdfPath = [rootPath stringByAppendingPathComponent:#"Nick.pdf"];
// NSLog(#"pdf is at %#",pdfPath);
// UIGraphicsBeginPDFContextToFile(pdfPath, CGRectZero, nil);
NSMutableData *data = [[NSMutableData alloc] initWithCapacity:100000];
UIGraphicsBeginPDFContextToData(data, CGRectZero, nil);
CFRange currentRange = CFRangeMake(0, 0);
NSInteger currentPage = 0;
BOOL done = NO;
do
{
UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0, 612, 792), nil);
currentPage++;
// [self drawPageNumber:currentPage];
currentRange = [self renderPage:currentPage withTextRange:currentRange andFramesetter:framesetter];
if (currentRange.location == CFAttributedStringGetLength((CFAttributedStringRef)currentText)) done = YES;
}
while (!done);
UIGraphicsEndPDFContext();
UIImage* image = [UIImage imageWithData:data];
assert(image);
UIImageWriteToSavedPhotosAlbum(image, self, nil, nil);
CFRelease(framesetter);
}
else NSLog(#"Could not create the framesetter needed to lay out the atrributed string.");
CFRelease(currentText);
}
else NSLog(#"Could not create the attributed string for the framesetter");
}
- (CFRange)renderPage:(NSInteger)pageNum withTextRange:(CFRange)currentRange andFramesetter:(CTFramesetterRef)framesetter
{
CGContextRef currentContext = UIGraphicsGetCurrentContext();
CGContextSetTextMatrix(currentContext, CGAffineTransformIdentity);
CGRect frameRect = CGRectMake(72, 72, 468, 648);
CGMutablePathRef framePath = CGPathCreateMutable();
CGPathAddRect(framePath, NULL, frameRect);
CTFrameRef frameRef = CTFramesetterCreateFrame(framesetter, currentRange, framePath, NULL);
CGPathRelease(framePath);
CGContextTranslateCTM(currentContext, 0, 792);
CGContextScaleCTM(currentContext, 1.0, -1.0);
CTFrameDraw(frameRef, currentContext);
currentRange = CTFrameGetVisibleStringRange(frameRef);
currentRange.location += currentRange.length;
currentRange.length = 0;
CFRelease(frameRef);
return currentRange;
}
Save the mutable data to your documents directory
[data writeToFile:filePath atomically:YES]
Here's an example:
+(void) saveData: (NSData*) data ToFileName: (NSString*) filename {
// Retrieves the document directories from the iOS device
NSArray* documentDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES);
NSString* documentDirectory = [documentDirectories objectAtIndex:0];
NSString* documentDirectoryFilename = [documentDirectory stringByAppendingPathComponent: filename];
// instructs the mutable data object to write its context to a file on disk
[data writeToFile:documentDirectoryFilename atomically:YES];
//NSLog(#"documentDirectoryFileName: %#",documentDirectoryFilename);
}
As for displaying the generated PDF on the device, the UIWebView object supports loading PDF files from NSData. Here is an example:
[self.webView loadData:pdfData MIMEType:#"application/pdf" textEncodingName:#"utf-8" baseURL:nil];
It is possible to attach an NSData object to an email as well. Here is an example:
//Check if we can send e-mails
if ([MFMailComposeViewController canSendMail]) {
//Create the Email view controller
MFMailComposeViewController *controller = [[MFMailComposeViewController alloc] init];
controller.mailComposeDelegate = self;
//Set the subject and body
[controller setSubject:#"Email Subject"];
[controller setMessageBody:#"Email body" isHTML:NO];
//Set the email address
[controller setToRecipients:#"test#test.com"];
//Add the current PDF as an attachment
NSString *fileName = #"file.pdf";
[controller addAttachmentData:self.retrievedPDF mimeType:#"application/pdf" fileName:fileName];
// show the email controller modally
[self.navigationController presentModalViewController: controller animated: YES];
}
Instead of writing the PDF to an NSMutableData object, write it to a file using UIGraphicsBeginPDFContextToFile.
The first argument is the file path. The best place would be the Documents directory. There are then many different ways to get the file out of the app:
iTunes file sharing
Email
iCloud
Sending to a 3rd party server (Dropbox, Box, Google Drive, etc.)
Open in another iOS app using UIDocumentInteractionController.

Setting image property of UIImageView causes major lag

Let me tell you about the problem I am having and how I tried to solve it. I have a UIScrollView which loads subviews as one scrolls from left to right. Each subview has 10-20 images around 400x200 each. When I scroll from view to view, I experience quite a bit of lag.
After investigating, I discovered that after unloading all the views and trying it again, the lag was gone. I figured that the synchronous caching of the images was the cause of the lag. So I created a subclass of UIImageView which loaded the images asynchronously. The loading code looks like the following (self.dispatchQueue returns a serial dispatch queue).
- (void)loadImageNamed:(NSString *)name {
dispatch_async(self.dispatchQueue, ^{
UIImage *image = [UIImage imageNamed:name];
dispatch_sync(dispatch_get_main_queue(), ^{
self.image = image;
});
});
}
However, after changing all of my UIImageViews to this subclass, I still experienced lag (I'm not sure if it was lessened or not). I boiled down the cause of the problem to self.image = image;. Why is this causing so much lag (but only on the first load)?
Please help me. =(
EDIT 3: iOS 15 now offers UIImage.prepareForDisplay(completionHandler:).
image.prepareForDisplay { decodedImage in
imageView.image = decodedImage
}
or
imageView.image = await image.byPreparingForDisplay()
EDIT 2: Here is a Swift version that contains a few improvements. (Untested.)
https://gist.github.com/fumoboy007/d869e66ad0466a9c246d
EDIT: Actually, I believe all that is necessary is the following. (Untested.)
- (void)loadImageNamed:(NSString *)name {
dispatch_async(self.dispatchQueue, ^{
// Determine path to image depending on scale of device's screen,
// fallback to 1x if 2x is not available
NSString *pathTo1xImage = [[NSBundle mainBundle] pathForResource:name ofType:#"png"];
NSString *pathTo2xImage = [[NSBundle mainBundle] pathForResource:[name stringByAppendingString:#"#2x"] ofType:#"png"];
NSString *pathToImage = ([UIScreen mainScreen].scale == 1 || !pathTo2xImage) ? pathTo1xImage : pathTo2xImage;
UIImage *image = [[UIImage alloc] initWithContentsOfFile:pathToImage];
// Decompress image
if (image) {
UIGraphicsBeginImageContextWithOptions(image.size, NO, image.scale);
[image drawAtPoint:CGPointZero];
image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
// Configure the UI with pre-decompressed UIImage
dispatch_async(dispatch_get_main_queue(), ^{
self.image = image;
});
});
}
ORIGINAL ANSWER: It turns out that it wasn't self.image = image; directly. The UIImage image loading methods don't decompress and process the image data right away; they do it when the view refreshes its display. So the solution was to go a level lower to Core Graphics and decompress and process the image data myself. The new code looks like the following.
- (void)loadImageNamed:(NSString *)name {
dispatch_async(self.dispatchQueue, ^{
// Determine path to image depending on scale of device's screen,
// fallback to 1x if 2x is not available
NSString *pathTo1xImage = [[NSBundle mainBundle] pathForResource:name ofType:#"png"];
NSString *pathTo2xImage = [[NSBundle mainBundle] pathForResource:[name stringByAppendingString:#"#2x"] ofType:#"png"];
NSString *pathToImage = ([UIScreen mainScreen].scale == 1 || !pathTo2xImage) ? pathTo1xImage : pathTo2xImage;
UIImage *uiImage = nil;
if (pathToImage) {
// Load the image
CGDataProviderRef imageDataProvider = CGDataProviderCreateWithFilename([pathToImage fileSystemRepresentation]);
CGImageRef image = CGImageCreateWithPNGDataProvider(imageDataProvider, NULL, NO, kCGRenderingIntentDefault);
// Create a bitmap context from the image's specifications
// (Note: We need to specify kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little
// because PNGs are optimized by Xcode this way.)
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef bitmapContext = CGBitmapContextCreate(NULL, CGImageGetWidth(image), CGImageGetHeight(image), CGImageGetBitsPerComponent(image), CGImageGetWidth(image) * 4, colorSpace, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little);
// Draw the image into the bitmap context
CGContextDrawImage(bitmapContext, CGRectMake(0, 0, CGImageGetWidth(image), CGImageGetHeight(image)), image);
// Extract the decompressed image
CGImageRef decompressedImage = CGBitmapContextCreateImage(bitmapContext);
// Create a UIImage
uiImage = [[UIImage alloc] initWithCGImage:decompressedImage];
// Release everything
CGImageRelease(decompressedImage);
CGContextRelease(bitmapContext);
CGColorSpaceRelease(colorSpace);
CGImageRelease(image);
CGDataProviderRelease(imageDataProvider);
}
// Configure the UI with pre-decompressed UIImage
dispatch_async(dispatch_get_main_queue(), ^{
self.image = uiImage;
});
});
}
I think, the problem could be Images themselves. For example - I got in one of my projects 10 images 640x600 layered with alpha transparency on each other. When I try to push or pop viewcontroller from this viewcontroller.. it lags a lot.
when I leave only few images or use quite smaller images - no lag.
P.S. tested on sdk 4.2 ios5 iphone 4.

contacts data in xcode

Everybody..
I am trying to develop an app for iPhone which basicly deals with ABAddressBook and contacts data...
My goal is to send all the contacts data (at first step, names and phones) in a file by e-mail..
Now, I am trying to reach the contacts data, and I want to add them to two different arrays, names and phones arrays..
At first, I am trying to see all the datas in the screen when i pressed a button "List Contacts". the datas should be seen on the screen. and then when i pressed the second button "Send Contacts", it should send the file to an e-mail account.. This is how my apps will work..
I am having problems at showing the data on the screen.. I wrote something but it doesn't give anything on the screen in a textView..
Can you help me to solve this problem?
Here's the code for listing the contacts (listCon method):
-(IBAction)listCon:(id)sender
{
NSMutableArray *names = [[NSMutableArray alloc] init];
NSMutableArray *numbers1= [[NSMutableArray array] init];
NSMutableArray *numbers2= [[NSMutableArray array] init];
NSMutableArray *numbers3= [[NSMutableArray array] init];
ABAddressBookRef addressBook = ABAddressBookCreate();
if (addressBook != nil)
{
NSLog(#"Successfully accessed the address book.");
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFIndex nPeople= ABAddressBookGetPersonCount(addressBook);
NSUInteger peopleCounter = 0;
for (peopleCounter = 0;peopleCounter < nPeople; peopleCounter++)
{
ABRecordRef thisPerson = CFArrayGetValueAtIndex(allPeople,peopleCounter);
NSString *contactFirstLast = [NSString stringWithFormat:#"%,%",ABRecordCopyValue(thisPerson, kABPersonFirstNameProperty), ABRecordCopyValue(thisPerson,kABPersonLastNameProperty)];
[names insertObject:contactFirstLast atIndex:peopleCounter];
ABMultiValueRef phoneNumbers = ABRecordCopyValue(thisPerson,kABPersonPhoneProperty);
NSString *firstPhone = (__bridge_transfer NSString*) ABMultiValueCopyValueAtIndex(phoneNumbers, 0);
NSString *secondPhone = (__bridge_transfer NSString*) ABMultiValueCopyValueAtIndex(phoneNumbers, 1);
NSString *thirdPhone = (__bridge_transfer NSString*) ABMultiValueCopyValueAtIndex(phoneNumbers, 2);
[numbers1 insertObject:firstPhone atIndex:peopleCounter];
[numbers2 insertObject:secondPhone atIndex:peopleCounter];
[numbers3 insertObject:thirdPhone atIndex:peopleCounter];
}
}
myView.text=[names componentsJoinedByString:#"\n\n"];
myView.text=[numbers1 componentsJoinedByString:#"\n\n"];
myView.text=[numbers2 componentsJoinedByString:#"\n\n"];
myView.text=[numbers3 componentsJoinedByString:#"\n\n"];
}
Just glancing at your code, you can't do this:
NSString *contactFirstLast = [NSString stringWithFormat:#"%,%",ABRecordCopyValue(thisPerson, kABPersonFirstNameProperty), ABRecordCopyValue(thisPerson,kABPersonLastNameProperty)];
There are several errors: first off % in your stringWithFormat: is not a format specifier; you probably are thinking of %#. Second off, copying the value of kABPersonFirstNameProperty will return a CFStringRef, and that's not what you want to display the name in a text field. You'll have to toll-free bridge the result of ABRecordCopyValue(). You can do this by adding this line - (__bridge_transfer NSString *) - in front of your ABRecordCopyValue()'s. With all the corrections, it should look like this:
NSString *contactFirstLast = [NSString stringWithFormat:#"%#,%#", (__bridge_transfer NSString *)ABRecordCopyValue(thisPerson, kABPersonFirstNameProperty), (__bridge_transfer NSString *)ABRecordCopyValue(thisPerson,kABPersonLastNameProperty)];
Hope this help (might not cover all errors)!

Convert PDF pages to images with COCOA

I am having problem with PDF conversion to images. I would like to create an image file for every page in PDF document.
This is the code I am using and works fine. Every page gets converted into the image, but I have problem with image resolution. I don't know how to set the resolution of the output images. Can someone help me out?
NSData *pdfData = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://localhost/test/test.pdf"]];
NSPDFImageRep *img = [NSPDFImageRep imageRepWithData:pdfData];
NSFileManager *fileManager = [NSFileManager defaultManager];
int count = [img pageCount];
for(int i = 0 ; i < count ; i++) {
[img setCurrentPage:i];
NSImage *temp = [[NSImage alloc] init];
[temp addRepresentation:img];
NSBitmapImageRep *rep = [NSBitmapImageRep imageRepWithData:[temp TIFFRepresentation]];
NSData *finalData = [rep representationUsingType:NSJPEGFileType properties:nil];
NSString *pageName = [NSString stringWithFormat:#"Page_%d.jpg", [img currentPage]];
[fileManager createFileAtPath:[NSString stringWithFormat:#"%#/%#", #"/Users/mac/Desktop/", pageName] contents:finalData attributes:nil];
}
Thanks a lot!
Since NSPDFImageRep is a subclass of NSImageRep, couldn't you use the [NSImageRep drawInRect:] method?
Link: http://developer.apple.com/mac/library/documentation/cocoa/reference/ApplicationKit/Classes/NSImageRep_Class/Reference/Reference.html#//apple_ref/doc/uid/20000346-drawInRect_
The simplest way would be to use the ImageIO framework. Feed the PDF data to an image source to get a CGImage; feed that object to an image destination to generate (and optionally save in the same step) the JPEG data. In the latter step, you can specify the resolution among the image properties; see “Individual Image Properties” in the documentation.
Don't forget to finalize your destination. It's vital.

Resources