Show taken images from camera in a ScrollView - ios

I have a simple application with only one button.
When user clicks on it, he can take a pictures, click "Done" in the camera and then can save it and see it on the ScrollView.
However, when he is taking another picture and clicking "Done" in the camera, the new picture overwrites the previous one and he can see only the picture that he has taken.
I want to save all these pictures and then if the user takes 4-5 pictures, he can see all of them by scrolling them.
Here is my code, im not sure why it is not working.
- (IBAction)Camera:(id)sender {
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.allowsEditing = YES;
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
[self presentViewController:picker animated:YES completion:NULL];
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
NSMutableArray *images = [NSMutableArray arrayWithCapacity:[info count]];
for (UIView *v in [_scrollView subviews]) {
[v removeFromSuperview];
}
[self dismissViewControllerAnimated:YES completion:nil];
UIImage* image=[info valueForKey:#"UIImagePickerControllerEditedImage"];
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
UIImageView *imageview = [[UIImageView alloc] initWithImage:image];
[_scrollView addSubview:imageview];
[images addObject:image];
self.chosenImages = images;
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
[_scrollView setPagingEnabled:YES];
}
And in header i have an array of chosenImages
#property (nonatomic, copy) NSArray *chosenImages;

There are lots of things wrong with your code. Every time the user picks an image, you remove all the subviews from your scroll view, then add just the single selected image.
You have an array chosenImages which you might use to hold all the selected images, but you replace it with a new array, images, which only contains the single newly selected image.
You allocate images as a mutable array with enough capacity for the count of the info dictionary you get in didFinishPickingMediaWithInfo, but there's no point to doing that. The count of that dictionary is going to be the number of key/value pairs in the dictionary, which does not reflect the number of images the user selected (I believe the number of images the user selected will always be 1, ignoring the different formats like the original image and the (possible) edited image.)
I would suggest leaving the previous images in your scroll view, tracking the number and placement of those images, and simply adding a new image to the scroll view after the user picks.
You might think about using a UIPageViewController in page scroll mode rather than a raw scroll view. It manages paged scrolling much better than a scrollview will. There is a sample app from Apple called PhotoScroller (link) that even supports tiled rendering of the images, pinch-to-zoom, and panning around an image. It would be pretty easy to stitch that code into your app for handling these images. (You might not decide to deal with the tiled images - I adapted the PhotoScroller code, with tiled image support, into a client project, and generating the image tiles is a fair amount of work.)

Assuming that self.chosenImages is of NSMutableArray type, try this
[self.chosenImages addObjectsFromArray:images]
instead of
self.chosenImages = images;
and if it isn't mutable, you can always set it like so:
NSMutableArray *newArray = [self.chosenImages mutableCopy];
newArray = [newArray addObjectsFromArray:images];
self.chosenImages = [newArray copy];

Related

How to add animate images and text in the same view programatically?

I am currently learning iOS development and I want to develop an iOS app where there is an animated image at the beginning top of the View Controller and a lot of text just after it. Please have a look at the picture below:
I have thought about the codes for both the image animation at the top and the large amount of text just after it. I was wondering whether someone could please review them and tell me whether they are fine or not.
The codes for both the image animation and the large amount of text will be placed inside the viewDidLoad method of the implementation file of the controller like this:
- (void)viewDidLoad
{
[super viewDidLoad];
// codes for image animation
// codes for large amount of text to be displayed
}
IMAGE ANIMATION CODES
For the image animation, I am going to use 5 png pictures: A.png, B.png, C.png, D.png and E.png. The slide show will start from A, then move on to B, then to C, to D and finally to E. All the 5 pictures are added to my project in Xcode. Below are the codes:
NSArray *imagelist = [[NSArray alloc] initWithObjects: [UIImage imageNamed:#"A.png"], [UIImage imageNamed:#"B.png"], [UIImage imageNamed:#"C.png"], [UIImage imageNamed:#"D.png"], [UIImage imageNamed:#"E.png"],nil];
UIImageView *animationImageView = [[UIImageView alloc] initWithFrame: CGRectMake(5,5,90,180)];
animationImageView.animationImages = imagelist;
animationimageView.animationDuration = 10;
[self.view addSubView:animationimageView];
[animationImageView startAnimating];
LARGE AMOUNT OF TEXT CODES
For the text, I have not added all the necessary text....because there is a lot more. That is why I need the text object to be scrollable. Below are the codes:
UITextView *largeText = [[UITextView alloc] initWitthFrame: CGRectMake(5,100,90,180)];
largeText.text = #"In organizations, we must work with and for others. To be able to mutually achieve our goals, we must be able to relate to others effectively. These leadership tips will help you do just that:
1)Catch people doing things right and then let them know that they are doing things right
2)Use feedback to stay informed about what other people are doing in your area of responsibility and authority
3)Have regular, focused meetings regarding the projects that you are responsible for
4)Provide adequate instructions. Time is lost if things are not done correctly
5)Train others to do jobs. You cannot do them all, nor can others do them if they have not been trained
6)Expect others to succeed. It becomes a self-fulfilling prophecy when you believe others are loyal, dedicated and doing a good job";
largeText.font = [UIFont fontWithName:#"TimesNewRomanPSMT" size:18];
largeText.editable = NO;
largeText.scrollEnabled = YES;
[self.view addSubView:largeText];
Please review the codes and can someone tell me whether the codes are fine or not.
Thanks for reading.
NSArray *imagelist = [[NSArray alloc] initWithObjects: [UIImage imageNamed:#"A.png"], [UIImage imageNamed:#"B.png"], [UIImage imageNamed:#"C.png"], [UIImage imageNamed:#"D.png"], [UIImage imageNamed:#"E.png"],nil];
UIImageView *animationImageView = [[UIImageView alloc] initWithFrame: CGRectMake(5,5,90,180)];
[self.view addSubView:animationimageView];
NSTimeInterval delay=0.0;
for (NSInteger i=0; i<[imagelist count]; i++) {
delay+=3.0;
[UIView animateWithDuration:0.5 delay:delay options:UIViewAnimationOptionCurveLinear animations:^{
animationImageView.image=[imagelist objectAtIndex:i];
}completion:nil];
}

Zoom and Pan on a UIPageViewController

I have a simple application which consists of a UITableViewController with cells of Languages. When the user clicks a specific language, it brings up a UIPageViewController to show horizontally, 6 images in a pageView. That part is working really well and the images are loading.
I have implemented this, using this tutorial: http://code.tutsplus.com/tutorials/using-scrollstyle-with-uipageviewcontroller--mobile-13551.
I would like to achieve a zoom and pan functionality within this as well now.
I have zoom working with the following code.
CGFloat scale = pinchRecognizer.scale;
self.pageViewController.view.transform = CGAffineTransformScale(self.pageViewController.view.transform, scale, scale);
pinchRecognizer.scale = 1.0;
The problem is that the zoom is always in the centre of the image with no way to pan around the image like you can in a normal Photo on an iOS device.
I have found lots of good tutorials on how to achieve this, like http://iosdeveloperzone.com/2012/07/07/tutorial-all-about-images-part-2-panning-zooming-with-uiscrollview/ as an example. However, my confusion stems from the very first part.
I am loading my UIPageViewController using a NSArray:
self.modelArray = [NSMutableArray arrayWithObjects:[[ImageModel alloc] initWithImageName:#"3facts-english-page1.jpg"], [[ImageModel alloc] initWithImageName:#"3facts-english-page2.jpg"], [[ImageModel alloc] initWithImageName:#"3facts-english-page3.jpg"], nil];
How to I extract each image into a UIImageView?
I can see that fundamentally, I need to have most of this code to enable the Pan:
UIImage* image = [UIImage imageNamed:#"KinkakuJi"];
self.imageView.image = image;
[self.imageView sizeToFit];
self.scrollView.contentSize = image.size;
In my case however, I'm not loading a single UIImage but rather a NSArray. How do I extract the UIImage from the NSArray to make this pan happen?
Any thoughts on this would really be appreciated.

Scrollview Images creates issue

I am pick Images using Camera in my app & try to show in horizontal scrollview.
But the images are overlapping
My code
-(IBAction)act_photo:(id)sender
{
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
//picker.allowsEditing = YES;
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
[self presentViewController:picker animated:YES completion:NULL];
}
#pragma mark - Image Picker via Camera
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
UIImage *chosenImage = info[UIImagePickerControllerOriginalImage];
[picker dismissViewControllerAnimated:YES completion:^{
[arr_images insertObject:chosenImage atIndex:0];
[self scrollImages_Setup2];
}];
}
-(void)scrollImages_Setup2
{
for (int k=0; k<arr_images.count; k++) {
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake((CGRectGetWidth(scl.frame) * k) + CGRectGetWidth(scl.frame), 0, CGRectGetWidth(scl.frame), CGRectGetHeight(scl.frame))];
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.image=[arr_images objectAtIndex:k] ;
[scl addSubview:imageView];
}
scl.contentSize = CGSizeMake((CGRectGetWidth(scl.frame) * arr_images.count)+CGRectGetWidth(scl.frame), CGRectGetHeight(scl.frame));
}
Problem
Image1
Image 2
As shown above first I was taken Landscape Image2 & then I was taken Portrait Image 1 .
but as you see, Image 1 has background of Image2.
I think this is because there is something going wrong with scrollview?
Possiblity 2(mostly) Scrollview keeps strong reference of Imageview evenif it is deleted from array
Let me know how to solve this?
Help me to solve this
Thanks
You need to set Y value in you loop, your image Y value same any time,
Each time you take a new image, your completion-Handler puts the new image as the first element into your array and then calls [self scrollImages_Setup2]; where you iterate over all elements in your array and add them as new subviews to your scrollview.
When you take the first image (Image1) it's getting added to the array and then added as and subview to your scrollview. When you take the second image (Image2) it's getting added to the array as the first element. So then there are two elements in the array (Image2 and Image1) which are both getting added as subview to the scrollview. But Image1 has already been added to the scrollview, so that's causing your problem.
A solution to your problem could be either to always add only the new image and calculate the x position with the number of elements in your array, or to always remove all subviews before you add and layout all images again.

Objective-C Camera Crop Size

I have a routine that I use to trigger the camera to take a photo. After the camera takes the photo the user is then given an option to crop the image by default before the delegate passes me back the UIImage. Is there any way that I can pass in a dynamic CGRect to make this default crop area a specific size? One thing I should mention is that the application is a landscape iPad application.
Here is a code sample:
-(void)triggerCamera:(id)sender
{
UIImagePickerController *camera = [[UIImagePickerController alloc] init];
camera.delegate = self;
camera.allowsEditing = YES;
camera.sourceType = UIImagePickerControllerSourceTypeCamera;
//pass in some sort of CGRect ??
[self presentViewController:camera animated:YES completion:NULL];
}
-(void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info {
UIImage *img = [info objectForKey: UIImagePickerControllerOriginalImage];
//process my image further
}
Unfortunately you can't set crop size. I was dealing with same problem over 2 years ago and I got stuck with creating my own viewController for cropping image.
Maybe take a look at GKImagePicker on GitHub. This project hasn't had much activity in the past few months (maybe more), but could be worth a shot. It even comes with an option to have a resizable crop area. I have not tried it myself, but the implementation looks to be pretty simple:
self.imagePicker = [[GKImagePicker alloc] init];
self.imagePicker.cropSize = CGSizeMake(320, 90);
self.imagePicker.delegate = self;
[self presentModalViewController:self.imagePicker.imagePickerController animated:YES];

Custom Overlay with UIImagePickerControllerSourceTypeSavedPhotosAlbum

I need to let the user select a photo from the Photo Library and be able to size and crop their image while using an Overlay image. Using UIImagePickerControllerSourceTypeCamera with cameraOverlayView is fine, but UIImagePickerControllerSourceTypeSavedPhotosAlbum does not support that property.
Strangely enough, when I add the overlay view as a subView with alpha set at half, the overlay appears on the Photo selection screen, but this wont fly with Apple's approval process.
-(void)choosePhotoDialog:(id)sender
{
UIBarButtonItem * barThing = (UIBarButtonItem*)sender;
OverlayView * overlay = [[OverlayView alloc] initWithFrame: CGRectMake(0, 0, SCREEN_WIDTH_IPHONE, SCREEN_HEIGTH_IPHONE)
andPhotoOverlay: [dict objectForKey:#"imageUrl"]];
[overlay setUserInteractionEnabled: NO];
UIImagePickerController * picker = [[UIImagePickerController alloc] init];
switch (barThing.tag)
{
case 0: [picker setSourceType: UIImagePickerControllerSourceTypeCamera];
[picker setShowsCameraControls: YES];
[picker setCameraOverlayView: overlay];
break;
case 1: [picker setSourceType: UIImagePickerControllerSourceTypeSavedPhotosAlbum];
[picker.view addSubview: overlay];
[overlay setAlpha: 0.5f];
break;
}
[picker setDelegate: self];
[picker setAllowsEditing: YES];
[picker setNavigationBarHidden: YES];
[picker setWantsFullScreenLayout: YES];
[self presentModalViewController:picker animated:YES];
[picker release];
}
Question
What is the correct way to allow a user to select a photo from the PhotoLibrary with an Overlay using UIImagePickerControllerSourceTypeSavedPhotosAlbum?
Resolved
Basically, I needed to write 3 separate classes and combine them to create my own custom photo editing view, which also saves pinch / zoom / rotate edits.
I ended up writing several classes:
An OverlayView class which is a UIView and simply retrieves the .png image with transparency and is the bottom-most layer.
An InteractiveWallpaper class which is a UIImageView and handles all of the touch events, including the transformation events.
And finally, an EditingView class which is a UIViewController. This adds the 2 views previously mentioned as well as saves the photo that the user edited.
This also allowed me to customize the behavior of the view. When the user touches the imported photo, the top-most photo decreases it's alpha value, allowing the user to still see the overlay while the imported photo is more visible.

Resources