Changing the image in UIimageView - ios7

Hi I am new to ios programming,
I am trying to change the image of UIImageView outletImage
- (void)viewDidLoad
{
[super viewDidLoad];
dragView *dragViewCopy=[[dragView alloc]init];
newPic=[dragViewCopy imageChanger];
outletImage.image=[UIImage imageNamed:(NSString*)newPic];
NSLog(#"vc %#",newPic);
}
but it is not changing,inspite that the correct name of the image appears when i test it with NSLog
when i try this
outletImage.image=[UIImage imageNamed:(NSString*)#"bird.png];
it works
Can anybody help me about this
thanks

Your problem appears to be that you're trying to load an image from disk (or whatever the iOS device's hard drive equivalent is) and the actual image you have (which comes from the "imageChanger") method is entirely within memory.
So instead of doing "[UIImage imageNamed:]", you may want to create your image using "[UIImage alloc] initWithData:" or use whatever actual object type "imageChanger" returns.

Related

Save position in UIImagePickerController

I am developing an app which allows you to select photos and place them into different positions. The workflow is basically:
Tap an area of the screen
UIImagePickerController displays
Select a photo
Photo displays in the tapped area of the screen
I would like it so that if the user goes through this workflow for a second time, the UIImagePickerController when displayed will be showing the same album, and position within that album, that the user was last at.
I've tried saving a reference to the UIImagePickerController, as well as the UIPopoverController, so that they are created only once. However, every time I present the popover containing the UIImagePickerController, it is back at the main photos menu (eg. Camera Roll, Photo Library, My Photo Stream).
Any ideas for how to achieve what I'm after?
You can use ALAssetsLibrary . But this will cost you more effort. First time use – enumerateGroupsWithTypes:usingBlock:failureBlock: to list all album and remember user's choice. And at second time. Just use that album:ALAssetsGroup's – enumerateAssetsUsingBlock: to list all the images and videos. Apple has a few demo you can have a look PhotosByLocation MyImagePicker
keep a UIImagePickerController obj in .h class (for example imagePicker)
alloc the obj once (for example in viewDidLoad)
imagePicker = [[UIImagePickerController alloc] init];
imagePicker.delegate = self;
imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self.view addSubview:imagePicker.view];
imagePicker.view.hidden = YES;
imagePicker.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
imagePicker.view.bounds = CGRectMake(0,20,self.view.frame.size.width, self.view.frame.size.height);
In didFinishPickingMediaWithInfo
if([[info valueForKey:UIImagePickerControllerMediaType] isEqualToString:#"public.image"]){
imagePicker.view.hidden = YES;
}
When you want to show the imagePickerView just do
imagePicker.view.hidden = NO;
Just to point you to right direction. You can use asset library to show the images as a picker. You can use the apple sample code MyImagePicker. The method [[assetsLibrary] enumerateGroupsWithTypes:ALAssetsGroupAlbum usingBlock:^(ALAssetsGroup *group, BOOL *stop) can be used for photo album. Using the asset library you can check which image was selected last and then use the method,
- (void)enumerateAssetsAtIndexes:(NSIndexSet *)indexSet options:(NSEnumerationOptions)options usingBlock:(ALAssetsGroupEnumerationResultsBlock)enumerationBlock;
You can use this method next time to enumerate which image onwards you want to enumerate. This method can accept an indexSet as [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(index, count)] which should help to indicate the last selected image.
To know more about how to use asset library check this.
It should be possible to reach into the resulting UITableView and then find its content offset. You can do this by searching the subviews of the UIImagePickerController's view property for a table view.
for (UIView *view in controller.view) {
if ([view isKindOfClass:[UITableView class]]) {
contentOffset = [(UITableView *)view contentOffset];
}
}
When you represent the view controller, you will want to restore the content offset in a similar fashion.
Note, I haven't actually tested to see the view hierarchy of the UIImagePickerController. Verify its structure by printing its subviews. There is also no guarantee that the structure will stay the same, since you are diving into the private implementation (though it's important to note you are not actually using any private APIs so this is okay).
Use AlAssetsLibrary. It control the image & video capture under the application. there a demo on apple.
https://developer.apple.com/library/ios/#documentation/AssetsLibrary/Reference/ALAssetsLibrary_Class/Reference/Reference.html
look for this or
if you want to make a cutomize album for the image and video here a great example.
https://github.com/Kjuly/ALAssetsLibrary-CustomPhotoAlbum

set retina image in uiimageview

today i first run my app on my iphone but all my images (my background image too) were blurry, i read in the apple documentation and i understand that i should use a double pixel size (640X960 instead of 320X460). to set my image background i just use an uiiamgeview and set the image in the xib file. now, my question is how can i set the image from the .m file and not from my xib file. when i try to set the image from the .m file my image was much bigger then my uiimageview (i see only part from the image)?
thanks!
When using retina double sized images you don't actually have to do anything as far as loading them in code or in Interface Builder.
You just need to name the properly and make sure they're in your Xcode project.
For example if you had one image.png you'd need an image#2x.png in your Xcode project as well. iOS will automatically use the correct when when displaying on a Retina Device.
Update: In response to your comment.
This will create an UIImageView and set it to the size of the view. Its very similar to how most people do it in Interface Builder.
- (void)viewDidLoad
{
UIImageView *background = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"background.png"];
[background setFrame:CGRect(0.0,0.0,self.view.frame.size.width,self.view.frame.size.height)];
[self.view addSubview:background];
}

Memory management with image saved from UIImagePickerController

I'm writing an app in which the user takes a photo of them self, and then goes through a series of views to adjust the image using a navigation controller. This works perfectly fine if the user takes the photo with the front camera (set as default on devices that support it), but when I repeat the process I get about half way through and it crashes after throwing a memory warning.
After profiling in Instruments I see that my apps memory footprint holds at about 20-25 MB when using the lower resolution front camera image, but when using the back camera every view change adds another 33 MB or so until it crashes at about 350 MB (on a 4S)
Below is the code I'm using to handle saving the photo to the documents directory, and then reading that file location to set the image to a UIImageView. The "read" portion of this code is recycled through several view controllers (viewDidLoad) to set the image I saved as the background image in each view as I go.
I have removed all my image modification code to strip this down to the bear minimum attempting to isolate the problem, and I can't seem to find it. As it stands right now, all the app does is take a photo in the first view and then use that photo as the background image for about 10 more views, allocating as the user navigates through the view stack.
Now obviously the higher resolution photos would use more memory, but what I don't understand is that why the low resolution photos don't seem to be using more and more memory as I go, whereas the high resolution photos continuously use more and more until a crash.
How I am saving and reading the image:
- (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
UIImage *image = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
jpgData = UIImageJPEGRepresentation(image, 1);
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0];
filePath = [documentsPath stringByAppendingPathComponent:#"image.jpeg"];
[jpgData writeToFile:filePath atomically:YES];
[self dismissModalViewControllerAnimated:YES];
[disableNextButton setEnabled:YES];
jpgData = [NSData dataWithContentsOfFile:filePath];
UIImage *image2 = [UIImage imageWithData:jpgData];
[imageView setImage:image2];
}
Now I know that I could try scaling the image before I save it, which I plan on looking into next, but I don't see why this doesn't work as is. Maybe I was falsely under the impression that ARC automatically deallocated views and their subviews when they leave the top of the stack.
Can anyone shed some light on why I'm stock piling my devices memory? (Hopefully something simple I'm completely overlooking) Did I somehow manage to throw ARC out the window?
EDIT: How I call for the image in my other views
- (void)loadBackground
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0];
NSString *filePath = [documentsPath stringByAppendingPathComponent:#"image.jpeg"];
UIImage *image = [UIImage imageWithContentsOfFile:filePath];
[backgroundImageView setImage:image];
}
How navigation between my view controllers is established:
EDIT 2:
What my basic declarations look like:
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#interface PhotoPickerViewController : UIViewController <UIImagePickerControllerDelegate, UINavigationControllerDelegate>
{
IBOutlet UIImageView *imageView;
NSData *jpgData;
NSString *filePath;
UIImagePickerController *imagePicker;
IBOutlet UIBarButtonItem *disableNextButton;
}
#end
If relevant, how I call up my image picker:
- (void)callCameraPicker
{
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera] == YES)
{
NSLog(#"Camera is available and ready");
imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
imagePicker.delegate = self;
imagePicker.allowsEditing = NO;
imagePicker.cameraCaptureMode = UIImagePickerControllerCameraCaptureModePhoto;
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; for (AVCaptureDevice *device in devices)
{
if([[UIScreen mainScreen] respondsToSelector:#selector(scale)] && [[UIScreen mainScreen] scale] == 2.0)
{
imagePicker.cameraDevice = UIImagePickerControllerCameraDeviceFront;
}
}
imagePicker.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:imagePicker animated:YES];
}
else
{
NSLog(#"Camera is not available");
UIAlertView *cameraAlert = [[UIAlertView alloc] initWithTitle:#"Error"
message:#"Your device doesn't seem to have a camera!"
delegate:self cancelButtonTitle:#"Dismiss"
otherButtonTitles:nil];
[cameraAlert show];
}
}
EDIT 3: I logged viewDidUnload, and it was in fact not being called so I'm now calling loadBackground in viewWillAppear and making my backgroundImageView nil in viewDidDisappear. I expected this to help but it made no difference.
- (void)viewWillAppear:(BOOL)animated
{
[self loadBackground];
}
- (void)viewDidDisappear:(BOOL)animated
{
NSLog(#"ViewDidDisappear");
backgroundImageView = nil;
}
The relationship between UIImage and UIImageView is not necessarily intuitive for everyone.
UIImage is a high level representation of your image data - alone, it does nothing in terms of displaying the data.
UIImageView works with UIImage to allow you to display an image.
There is no reason why multiple instances of UIImageView cannot display the same UIImage. This is nice and efficient, because there is only one in-memory representation of the image data, being shared by multiple views.
What you seem to be doing is creating a new UIImage for each one of your views, by loading it from disk. So this is a poor general design in two respects: instantiating what is effectively the same UIImage over and over again, and re-loading the same image data from disk repeatedly.
Your memory problem is really a separate issue, where you are not properly releasing the image data you keep loading into UIImage objects and UIImageViews.
In theory, you should be able to take the very first UIImage you're getting from UIImagePickerController and simply pass that reference around to your views, without reloading from disk.
If you need to be saving and reloading from disk because of higher level functional requirements (e.g. because the image is being changed by the user and you want to keep saving it), you'll need to be sure you are fully tearing down the previous UIView, by removing it from the it's view hierarchy. It is helpful to setup a breakpoint in the dealloc method for the view to confirm it is being removed and dealloced, and make sure you set any iVar references to sub-views (it appears your backgroundImageView is an iVar) are set to nil. If you are not properly tearing down that backgroundImageView, it is continuing to hold a reference to the UIImage you set to it's image property.
There are a couple of things that are curious about the code you posted:
None of your view-callback implementations call super. That’s bad! Make extra sure that you are calling super in viewDidUnload and (if you implemented it) didReceiveMemoryWarning.
Make sure you implement didReceiveMemoryWarning in a meaningful way!
You really should not be re-creating that image over and over again! I assume you are not editing the actual image because you use JPEG compression on it which — even at 100% quality — will deteriorate your image with every save…
Check your implementation of viewDidUnload make sure to set every of your IBOutlets to nil.
ARC is not Pixie Dust™! It just saves you a bit of typing, it does not free you from designing and maintaining your object graphs!
From your question, I see at the very least these graphs that refer to your image:
image 1 <- image-view 1 <- view-controller 1 <- navigation-controller <- key window <- application
image 1 <- image-view 1 <- view 1 <- view-controller 1 <- navigation-controller <- key window <- application
This is repeated for every view-controller with an index shift on the view-controller, view, image view and image. While you have to have separate views, image-views for your view-controllers, I cannot think of a reason why you would want several copies of the same image.
So the first axe on your memory consumption clearly is to no longer create all those copies of the same image data — I’d estimate that this will get you half of the low-hanging memory savings.
The next thing is that ARC can only free the memory consumed by your objects if it is no longer referenced.
Memory wise, views are not exactly lightweight objects and when you build up a deep navigation stack you end up with gobs of them.
So you need to axe any unneeded strong references to those views, as well.
The level, at which this has to happen is the view-controller. The latest time at which this should happen is in the view-controller’s implementation of viewDidUnload.
Why the view-controller?
From what you described, the image itself is only referenced by the UIImageView — this is a bad choice, IMHO, but I digress…
UIViewController is designed to “know”, when its view is needed and when it’s safe to dispose of it — that’s why it implements didReceiveMemoryWarning and viewDidUnload:
If the memory pressure gets to high and the view-controller’s view is not “on screen” the root implementation of didReceiveMemoryWorning will let go of its view and call viewDidUnload upon itself, afterwards.
This is why you must call through to super in your implementations of both of those methods.
In addition, this is why if you have strong IBOutlets that refer to subviews of the view-controller’s view, you must nil them in viewDidUnload or the system cannot reclaim the memory they occupy.
At its heart UIViewController is a big-ass finite state-machine. All of those “something-will/did-whatever” callbacks are used to transition between those states and most of the default implementations do some very important book-keeping to keep all that state in order.
If you are not invoking them in your overrides, you˚ll end up in inconsistent states and bad things — like this out of memory crasher — happen.
Just create separate folder and save your Capture images in it. After your successful operation clear that folder data(or)folder.using the nsfilemager.

do I need to initialize the new view?

I admit I'm a newby to Objective-C but came pretty far, I guess. Now I'm having an issue and would need some help.
In my app I display images in portrait modes amongst other information and want to display them full screen in landscape mode. I learned that you'd do this defining a Landscape m, h and nib file and load this view when the device is moved to landscape orientation (working with an observer), right?
In portrait mode the images in the end depend on user interaction so the Landscape class needs to be told, which image to display. I created a putImage method in the Landscape class
-(void) putImage:(NSString *)theImage {
pict.image = [UIImage imageNamed: theImage];
NSLog(#"PICT %#",pict.image);
NSLog(#"IMAGE %#",theImage);
}
and call it from the portrait one and here comes the issue:
NSString *actualImage = [NSString stringWithFormat:#"Picture%i.jpg",selected];
pict.image = [UIImage imageNamed: actualImage];
[landscapeViewController putImage:actualImage];
that works perfectly every time except the very first one. So whatever I do I need to first make the App load a new image plus change to landscape orientation (being displayed no image) in any manner. Then after it always works displaying the correct images.
I added debug information and see that the correct image is assigned to pict in landscape class - however it seems it needs to be displayed before it really sets the image.
Any help you guys could give?
Not sure if this it it since your example code is pretty sparse. But when you load your first picture do you do that in init? If so, try to do it in viewWillAppear or viewDidAppear.
thank you for all the hints and tries to help. Now I found the solution myself ... here's what I did:
1) in the LandscapeViewController.h I defined an NSString:
#interface LandscapeViewController : UIViewController
{
IBOutlet UIImageView *pict;
NSString *actualImage;
}
2) I changed the putImage method to only assign the image name to my local NSSTRING variable:
-(void) putImage:(NSString *)theImage {
actualImage = theImage;
[actualImage retain];
}
3) loading the image I only do in viewWillAppear:
- (void)viewWillAppear:(BOOL)animated {
pict.image = [UIImage imageNamed: actualImage];
[super viewWillAppear:animated];
}
So the answer to my question is almost answered - I guess that this issue arose because I did set the image before I loaded the view first time so that it was not instanciated. I was able to call the method but had no Image Object to set ... does that sound logical to you guys?
Thank you all again!

Another IKImageView Question: copying a region

I'm trying to use the select and copy feature of the IKImageView. If all you want to do is have an app with an image, select a portion and copy it to the clipboard, it's easy. You set the copy menu pick to the first responder's copy:(id) method and magically everything works.
However, if you want something more complicated, like you want to copy as part of some other operation, I can't seem to find the method to do this.
IKImageView doesn't seem to have a copy method, it doesn't seem to have a method that will even tell you the selected rectangle!
I have gone through Hillegass' book, so I understand how the clipboard works, just not how to get the portion of the image out of the view...
Now, I'm starting to think that I made a mistake in basing my project on IKImageView, but it's what Preview is built on (or so I've read), so I figured it had to be stable... and anyway, now it's too late, I'm too deep in this to start over...
So, other than not using IKImageView, any suggestions on how to copy the select region to the clipboard manually?
EDIT actually, I have found the copy(id) method, but when I call it, I get
<Error>: CGBitmapContextCreate: unsupported parameter combination: 8 integer bits/component; 16 bits/pixel; 1-component color space; kCGImageAlphaPremultipliedLast; 2624 bytes/row.
Which obviously doesn't happen when I do a normal copy through the first-responder... I understand the error message, but I'm not sure where it's getting those parameters from...
Is there any way to trace through this and see how this is happening? A debugger won't help for obvious reasons, as well as the fact that I'm doing this in Mozilla, so a debugger isn't an option anyway...
EDIT 2 It occurs to me that the copy:(id) method I found may be copying the VIEW rather than copying a chunk of the image to the clipboard, which is what I need.
The reason I thought it was the clipboard copy is that in another project, where I'm copying from an IKImageView to the clipboard straight from the edit menu, it just sends a copy:(id) to the firstResponder, but I'm not actually sure what the firstresponder does with it...
EDIT 3 It appears that the CGBitmapContextCreate error is coming from [imageView image] which, oddly enough, IS a documented method.
It's possible that this is happening because I'm putting the image in there with a setImage:(id) method, passing it an NSImage*... Is there some other, more clever way of getting an NSImage into an IKImageView?
The -copy: method in IKImageView does what every other -copy: method does: it copies the current selection to the clipboard. It is, however, implemented as a private method in IKImageView for some reason.
You can just call it directly:
[imageView copy:nil];
This will copy whatever is currently selected to the clipboard.
I don't think there's a way to directly access the image content of the current selection in IKImageView using public methods, this is a good candidate for a bug report/feature request.
You can, however, use the private method -selectionRect to get a CGRect of the current selection and use that to extract the selected portion of the image:
//stop the compiler from complaining when we call a private method
#interface IKImageView (CompilerSTFU)
- (CGRect)selectionRect
#end
#implementation YourController
//imageView is an IBOutlet connected to your IKImageView
- (NSImage*)selectedImage
{
//get the current selection
CGRect selection = [imageView selectionRect];
//get the portion of the image that the selection defines
CGImageRef selectedImage = CGImageCreateWithImageInRect([imageView image],(CGRect)selection);
//convert it to an NSBitmapImageRep
NSBitmapImageRep* bitmap = [[[NSBitmapImageRep alloc] initWithCGImage:selectedImage] autorelease];
CGImageRelease(selectedImage);
//create an image from the bitmap data
NSImage* image = [[[NSImage alloc] initWithData:[bitmap TIFFRepresentation]] autorelease];
//in 10.6 you can skip converting to an NSBitmapImageRep by doing this:
//NSImage* image = [[NSImage alloc] initWithCGImage:selectedImage size:NSZeroSize];
return image;
}
#end
Ok, so the copy: nil fails, and the [imageView image] fails, but it turns out that I have another copy of the NSImage from when I added it into the view in the first place, so I could that. Also, CGImageCreateWithImageInRect expects a CGImageRef not an NSImage*, so I had to do some conversions.
In addition, for some reason the selection rectangle is flipped, either it's bottom origined, and the image is top, or the other way around, so I had to flip it.
And for some reason, the compiler suddenly started complaining that NSRect isn't the same type as CGRect (Which implies that it suddenly went from 32 to 64 bit or something... not sure why...)
Anyway, here is my copy of selectedImage:
- (NSImage*)selectedImage
{
//get the current selection
CGRect selection = flipCGRect(imageView, [imageView selectionRect]);
//get the portion of the image that the selection defines
struct CGImage * full = [[doc currentImage] CGImageForProposedRect: NULL context: NULL hints: NULL];
CGImageRef selectedImage = CGImageCreateWithImageInRect( full, selection);
//convert it to an NSBitmapImageRep
NSBitmapImageRep* bitmap = [[[NSBitmapImageRep alloc] initWithCGImage:selectedImage] autorelease];
CGImageRelease(selectedImage);
// //create an image from the bitmap data
NSImage* image = [[[NSImage alloc] initWithData:[bitmap TIFFRepresentation]] autorelease];
// //in 10.6 you can skip converting to an NSBitmapImageRep by doing this:
//NSImage* image = [[NSImage alloc] initWithCGImage:selectedImage size:NSZeroSize];
return image;
}
I wrote flipCGRect, and [doc currentImage] returns an NSImage*...