Take a screenshot of an UIView where its subviews are camera sessions - camera

I'm building an app where I need to take a screenshot of a view whose subviews are camera sessions (AVFoundation sessions). I've tried this code:
CGRect rect = [self.containerView bounds];
UIGraphicsBeginImageContextWithOptions(rect.size,YES,0.0f);
CGContextRef context = UIGraphicsGetCurrentContext();
[self.containerView.layer renderInContext:context];
UIImage *capturedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Which effectively gets me an UIImage with the views, only that the camera sessions are black:
I've tried the private method UIGetScreenImage() and works perfectly, but as Apple doesn't allows this, I can't use it. I've also tried the one in Apple's docs but it's the same. I've tracked the problem to AVFoundation sessions using layers. How can I achieve this? The app has a container view with two views which are stopped camera sessions.

If using iOS 7, it's fairly simple and you could do something like this from a UIViewController:
UIView *snapshotView = [self.view snapshotViewAfterScreenUpdates:YES];
You can also use this link from a widow: iOS: what's the fastest, most performant way to make a screenshot programatically?
For iOS 6 and earlier, I could only find the following Apple Technical Q&A: [How do I take a screenshot of my app that contains both UIKit and Camera elements?]
Capture the contents of your camera view.
Draw that captured camera content yourself into the graphics context that you are rendering your UIKit elements. (Similar to what you did in your code)

I too am currently looking for a solution to this problem!
I am currently out at the moment so I can't test what I have found, but take a look at these links:
Screenshots-A Legal Way To Get Screenshots
seems like its on the right track - here is the
Example Project (and here is the initial post)
When I manage to get it to work I will definitely update this answer!

Related

different background images for landscape and portrait view

I am developing an universal app where I have given a background image for a UIView using the following code.
UIImageView *imgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"backImage.png"];
[self.view addSubview:imgView];
[self.view sendSubviewToBack:imgView];
I have created the following images and added to the project,
backImage.png
backImage#2x.png
backImage-Portrait~ipad.png
backImage-Portrait#2x~ipad.png
backImage-Landscape~ipad.png
backImage-Landscape#2x~ipad.png
But it does not seem to take the correct images.
It works fine when I run the app on iphone (I mean it takes the backImage.png and backImage#2x.png accordingly) but when I run the app on ipad it does not use the ipad images, it still uses the iphone images.
Can anyone please tell what must be going wrong.
Thanks in advance.
You need to detect in your code what type of device is being used, and depending on that, choose the appropriate image.
See here: iOS detect if user is on an iPad
I may be wrong, but I don’t think UIImage will know whether to load the ‘portrait' or ‘landscape' version of an image, much less change them dynamically when you rotate your interface. I think you’re expecting a lot more magic then there is.
Those conventions work in the app launch snapshot, but I think that’s the extent of it?

blurred image from AVCaptureVideoPreviewLayer in iOS7

I am developing a iOS7 video recording application. The camera screen in our application requires to show a blurred backgound similar to the one shown in iOS7 control Center. While the video preview is being shown, we need to show the blurred control center.
As suggested in WWDC video 226, I have used the code provided below to get camera preview snapshot and then applying blur and setting this blurred image to my view.
UIGraphicsBeginImageContextWithOptions(_camerapreview.frame.size, NULL, 0);
[_camerapreview drawViewHierarchyInRect:rect];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
lightImage = [newImage applyLightEffect]
Here _camerapreview is a UIView which contains AVCaptureVideoPreviewLayer. The *newImage obtained from the context is for some reason black.
However if i use [_camerapreview snapshotView] returns me a UIview with previewlayer content. But there is no way to apply blur on UIview.
How can I get a blurred image from the camera preview layer?
I would suggest that you put your overlay onto the video preview itself as a composited video layer, and add a blur filter to that. (Check the WWDC AVFoundation sessions and the AVSimpleEditoriOS sample code for compositing images onto video) That way you're staying on the GPU instead of doing readbacks from GPU->CPU, which is slow. Then drop your overlay's UI elements on top of the video preview within a clear background UIView.
That should provide greater performance. As good as Apple? Well, they are using some private stuff developers don't yet have access to...
Quoting Apple from this Technical Q&A:
A: Starting from iOS 7, the UIView class provides a method
-drawViewHierarchyInRect:afterScreenUpdates:, which lets you render a snapshot of the complete view hierarchy as visible onscreen into a
bitmap context. On iOS 6 and earlier, how to capture a view's drawing
contents depends on the underlying drawing technique. This new method
-drawViewHierarchyInRect:afterScreenUpdates: enables you to capture the contents of the receiver view and its subviews to an image
regardless of the drawing techniques (for example UIKit, Quartz,
OpenGL ES, SpriteKit, AV Foundation, etc) in which the views are
rendered
In my experience regarding AVFoundation is not like that, if you use that method on view that host a preview layer you will only obtain the content of the view without the image of the preview layer. Using the -snapshotViewAfterScreenUpdates: will return a UIView that host a special layer. If you try to make an image from that view you won't see nothing.
The only solution I know are AVCaptureVideoDataOutput and AVCaptureStillImageOutput. Each one has its own limit. The first one can't work simultaneously with a AVCaptureMovieFileOutput acquisition, the latter makes the shutter noice.

View behaviour differences between IOS 5.x and IOS 4.x

I've been trying to animate an image view to slide upwards on the screen. The views height is also increased whilst the position is moved upwards.
On my iPhone 4S (5.x) the image view behaves as expected, the view only moves upwards as its height is increased, however on my iPhone 3G (4.1), the view moves down a little bit during this animation.
Such a level of accuracy is needed as the image view is used to create a non expensive shadow effect. Its alignment is important for the effect. The image is a resizable graphic.
This is how I change the position and size of the view
CGRect oldShadow = self.shaddowView.frame;
oldShadow.size.height = oldShadow.size.height+200;
oldShadow.origin.y = oldShadow.origin.y - 200;
self.shaddowView.frame =oldShadow;
This is how the image for the view is set up as resizable:
UIImage* shadow = [[UIImage imageNamed:#"shadow.png"] stretchableImageWithLeftCapWidth:20 topCapHeight:20];
self.shaddowView.image = shadow;
Thanks.
I used the following animation, with a border around not only the starting position but also the intended final position, so that I could confirm whether any undesired shifting of the view (other than the obvious upward expansion) took place, but it worked fine on iOS 4.2.1:
[UIView animateWithDuration:2.0
animations:^{
CGRect newImageFrame = imageView.frame;
newImageFrame.origin.y -= stretchBy;
newImageFrame.size.height += stretchBy;
imageView.frame = newImageFrame;
}];
I don't have iOS 4.1 device sitting around (my old 3G test phone is running iOS 4.2.1, the latest supported iOS version for that device), so I can't speak to that, but it's fine with iOS 4.2.1.
I have to confess, though, that I find it very unlikely that when you animate the changing of a frame, that the final frame would not be precisely what you specified it to be. If you NSLog the frame when you're done, it is not the correct value? Or are you saying that it momentarily moves during the animation but then ends up in the correct location? Or that it shifts down during animation and ends up in the wrong position even when the animation is done?
I wonder if there's something else going on (e.g. is your animated view a subview of a scroll view, which itself might be shifting? or is there some code not shown here that is accidentally further adjusting the frame after the animation? etc.). Seems like a little debugging should confirm whether the frame is actually not what you intended, or whether there is some other issue going on.
I originally answered suggesting shouldRasterize option, but if you're trying to support old iPhone 3G devices, then maybe that's not good enough. Definitely stutters a little on these old phones. Anyway, this was my original answer:
I assume you're doing this because the layer shadow feature is a little CPU intensive. But I've heard (but can't speak to it) that if you use the shouldRasterize option, it's a little better:
viewThatNeedsShadow.layer.shadowColor = [UIColor blackColor].CGColor;
viewThatNeedsShadow.layer.shadowOffset = CGSizeMake(3.0, 3.0);
viewThatNeedsShadow.layer.shadowOpacity = 0.5;
viewThatNeedsShadow.layer.shouldRasterize = YES;
viewThatNeedsShadow.clipsToBounds = NO;

UIImage resizableImageWithCapInsets: not working as expected

I'm writing my first iOS app targeting the iOS 5.0+ platform. I'm using the UIAppearance protocol to customize the applications UI.
I'm trying to change the backgrounds for UIBarButtonItem across the entire application. Due to the fact that my UIBarButtonItem's may change size depending on the text or icon used I'm trying to utilize UIImage resizableImageWithCapInsets: with my background png.
I originally found the code I needed on Ray Wenderlich. Using the same exact code, with an image that's pretty close to the one used in the aforementioned tutorial, I'm getting weird results. Maybe it's just my inexperience with Cocoa Touch.
Here is the code I'm using.
DreamsAppDelegate.m - customizeAppearance:
UIImage *btnBg = [[UIImage imageNamed:#"navBarButton-bg"]
resizableImageWithCapInsets:UIEdgeInsetsMake(0, 6, 0, 6)];
[[UIBarButtonItem appearance] setBackgroundImage:btnBg
forState:UIControlStateNormal
barMetrics:UIBarMetricsDefault];
Here is the png background image I'm trying to use
And here is the result (in the simulator)
The section of your image between the left and right, and between the top and bottom, is tiled to fill the space needed by the image. Try UIEdgeInsetsMake(15, 6, 15, 6).
To generalize, if your image has a continuous gradient, the repeated section should only be 1 pixel high. Since your button image is 31 pixels high, the top and bottom (the first and third arguments to UIEdgeInsetsMake) should add to 30. They don't have to be equal; UIEdgeInsetsMake(8, 6, 22, 6) will move the repeated section up, resulting in a paler background.
Also, is the file you've attached the plain or the retina ('#2x') version of the image? The insets have to be within the size of the plain version.
I have the exact same problem.
Another thing you can do is to set the resizingMode of UIImageResizingModeStretch. It solved my problem.
Hopwever, it's not available in IOS5. So my solution would be to do as everyone else said. Realize that the tileable side should be just one pixel. Most buttons do not change much in the middle anyway.
So, use this code:
-(UIImage *) resizableImageWithCapInsets2: (UIEdgeInsets) inset
{
if ([self respondsToSelector:#selector(resizableImageWithCapInsets:resizingMode:)])
{
return [self resizableImageWithCapInsets:inset resizingMode:UIImageResizingModeStretch];
}
else
{
float left = (self.size.width-2)/2;//The middle points rarely vary anyway
float top = (self.size.height-2)/2;
return [self stretchableImageWithLeftCapWidth:left topCapHeight:top];
}
}

iOS UIImageView smooth Image presentation

One of the ways to improve user experience in iOS while showing images is to download them asynchronously without blocking the main thread and showing them....
But I want to add something to this -
Initially when there is no image,show a spinner while the async download has started.
After the download cache the image on local iOS disk for later use.
After the download populate the image part of UIImageView.
And dont just plonk the image into view for user. Showly Fade in the user (i.e. from alpha 0.0 to 1.0)
I have been using SDWebImage for sometime now. It works well but does not satisfy my 1st requirement (about spinner) and 4th.
Is there any help out there to satisfy all this?
Three20 http://www.three20.info has a TTImageView class that statisfies 2-3, you can subclass it and overwrite setImage: and create the fade animation there. (or just modify TTImageView.m directly).
Spinner is easy as well when you modify TTImageView you can add a TTActivityView on top and remove it on setImage: