I have 3 images. I load one by one to camera overlay image. Then i need to take snapshot. But when i click button it take snapshot of particular image. When i put imageName.png in captureStillImageWithOverlay it take snapshot of that image only, it won't taking other images when present in overlay
Button click code:
- (void)ButtonPressed {
[[self captureManager] captureStillImageWithOverlay:[UIImage imageNamed:#"img2.png"]];
}
Load images:
-(void)loadNextPage:(int)index
{
int countFlag=0;
for(int i=index*4;i<(index+1)*4;i++)
{
UIButton *imageView=[[UIButton alloc]initWithFrame:CGRectMake((320*index)+countFlag*80+ 2, 5, 75, 75)];
imageView.tag=i+1;
[imageView addTarget:self action:#selector(imageViewClicked:) forControlEvents:UIControlEventTouchUpInside];
[imageView.layer setBorderColor:[UIColor lightGrayColor].CGColor];
[imageView.layer setBorderWidth:1.0f];
switch ((i+1)%5) {
case 0:
[imageView setImage:[UIImage imageNamed:#"img1.png"] forState:UIControlStateNormal];
break;
case 1:
[imageView setImage:[UIImage imageNamed:#"img2.png"] forState:UIControlStateNormal];
break;
case 2:
[imageView setImage:[UIImage imageNamed:#"img3.png"] forState:UIControlStateNormal];
break;
}
[myScrollView addSubview:imageView];
[imageView release];
countFlag++;
}
}
Capture overlay image:
- (void)captureStillImageWithOverlay:(UIImage*)overlay
{
AVCaptureConnection *videoConnection = nil;
for (AVCaptureConnection *connection in [[self stillImageOutput] connections]) {
for (AVCaptureInputPort *port in [connection inputPorts]) {
if ([[port mediaType] isEqual:AVMediaTypeVideo]) {
videoConnection = connection;
break;
}
}
if (videoConnection) {
break;
}
}
NSLog(#"about to request a capture from: %#", [self stillImageOutput]);
[[self stillImageOutput] captureStillImageAsynchronouslyFromConnection:videoConnection
completionHandler:^(CMSampleBufferRef imageSampleBuffer, NSError *error) {
CFDictionaryRef exifAttachments = CMGetAttachment(imageSampleBuffer, kCGImagePropertyExifDictionary, NULL);
if (exifAttachments) {
NSLog(#"attachements: %#", exifAttachments);
} else {
NSLog(#"no attachments");
}
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];
UIImage *image = [[UIImage alloc] initWithData:imageData];
CGSize imageSize = [image size];
CGSize overlaySize = [overlay size];
UIGraphicsBeginImageContext(imageSize);
[image drawInRect:CGRectMake(0, 0, imageSize.width, imageSize.height)];
CGFloat xScaleFactor = imageSize.width / 320;
CGFloat yScaleFactor = imageSize.height / 480;
[overlay drawInRect:CGRectMake(30 * xScaleFactor, 100 * yScaleFactor, overlaySize.width * xScaleFactor, overlaySize.height * yScaleFactor)]; // rect used in AROverlayViewController was (30,100,260,200)
UIImage *combinedImage = UIGraphicsGetImageFromCurrentImageContext();
[self setStillImage:combinedImage];
UIGraphicsEndImageContext();
[image release];
[[NSNotificationCenter defaultCenter] postNotificationName:kImageCapturedSuccessfully object:nil];
}];
}
I take the reference from this url [http://www.musicalgeometry.com/?p=1681]
An overlay is just for presentation in the camera picker.
You also need to combine these images in your final UIImage (JPEG or TIFF or whatever) you save to disk.
Other people have had (and have solved) this same problem as you.
EDIT, here is some code that may help you out:
- (void)captureStillImageWithOverlay:(NSArray *) arrayOfImageFiles
{
AVCaptureConnection *videoConnection = nil;
for (AVCaptureConnection *connection in [[self stillImageOutput] connections]) {
for (AVCaptureInputPort *port in [connection inputPorts]) {
if ([[port mediaType] isEqual:AVMediaTypeVideo]) {
videoConnection = connection;
break;
}
}
if (videoConnection) {
break;
}
}
NSLog(#"about to request a capture from: %#", [self stillImageOutput]);
[[self stillImageOutput] captureStillImageAsynchronouslyFromConnection:videoConnection
completionHandler:^(CMSampleBufferRef imageSampleBuffer, NSError *error) {
CFDictionaryRef exifAttachments = CMGetAttachment(imageSampleBuffer, kCGImagePropertyExifDictionary, NULL);
if (exifAttachments) {
NSLog(#"attachements: %#", exifAttachments);
} else {
NSLog(#"no attachments");
}
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];
UIImage *image = [[UIImage alloc] initWithData:imageData];
CGSize imageSize = [image size];
UIGraphicsBeginImageContext(imageSize);
[image drawInRect:CGRectMake(0, 0, imageSize.width, imageSize.height)];
CGFloat xScaleFactor = imageSize.width / 320;
CGFloat yScaleFactor = imageSize.height / 480;
for(NSString * imageFileName in arrayOfImageFiles)
{
// images named #"img1" or #"img1.png" should work
UIImage * overlay = [UIImage imageNamed: imageFileName];
if(overlay)
{
CGSize overlaySize = [overlay size];
[overlay drawInRect:CGRectMake(30 * xScaleFactor, 100 * yScaleFactor, overlaySize.width * xScaleFactor, overlaySize.height * yScaleFactor)]; // rect used in AROverlayViewController was (30,100,260,200)
} else {
NSLog( #"could not find an image named %#", imageFileName);
}
}
UIImage *combinedImage = UIGraphicsGetImageFromCurrentImageContext();
[self setStillImage:combinedImage];
UIGraphicsEndImageContext();
[image release];
[[NSNotificationCenter defaultCenter] postNotificationName:kImageCapturedSuccessfully object:nil];
}];
}
Related
Im using AVCaptureSession for taking pictures and store pictures to album. When i click the button it takes the snapshot and store to album. But when i use landscape mode, then click the button it stores landscape modes result in upside down still images.
code:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[self setCaptureSession:[[AVCaptureSession alloc] init]];
[self addVideoInputFrontCamera:NO]; // set to YES for Front Camera, No for Back camera
[self addStillImageOutput];
[self setPreviewLayer:[[AVCaptureVideoPreviewLayer alloc] initWithSession:[self captureSession]] ];
[[self previewLayer] setVideoGravity:AVLayerVideoGravityResizeAspectFill];
CGRect layerRect = [[[self view] layer] bounds];
[[self previewLayer]setBounds:layerRect];
[[self previewLayer] setPosition:CGPointMake(CGRectGetMidX(layerRect),CGRectGetMidY(layerRect))];
[[[self view] layer] addSublayer:[self previewLayer]];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(saveImageToPhotoAlbum) name:kImageCapturedSuccessfully object:nil];
[[self captureSession] startRunning];
camera=[UIButton buttonWithType:UIButtonTypeCustom];
[camera setImage:[UIImage imageNamed:#"button.png"] forState:UIControlStateNormal];
[camera setFrame:CGRectMake(150, 10, 40, 30)];
[camera addTarget:self action:#selector(takephoto:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:camera];
}
Button for taking picture:
-(void)takephoto:(id)sender{
[self captureStillImage];
}
- (void)captureStillImage
{
AVCaptureConnection *videoConnection = nil;
for (AVCaptureConnection *connection in [[self stillImageOutput] connections]) {
for (AVCaptureInputPort *port in [connection inputPorts]) {
if ([[port mediaType] isEqual:AVMediaTypeVideo]) {
videoConnection = connection;
break;
}
}
if (videoConnection) {
break;
}
}
NSLog(#"about to request a capture from: %#", [self stillImageOutput]);
[[self stillImageOutput] captureStillImageAsynchronouslyFromConnection:videoConnection
completionHandler:^(CMSampleBufferRef imageSampleBuffer, NSError *error) {
CFDictionaryRef exifAttachments = CMGetAttachment(imageSampleBuffer, kCGImagePropertyExifDictionary, NULL);
if (exifAttachments) {
NSLog(#"attachements: %#", exifAttachments);
} else {
NSLog(#"no attachments");
}
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];
UIImage *image = [[UIImage alloc] initWithData:imageData];
[self setStillImage:image];
// [image release];
[[NSNotificationCenter defaultCenter] postNotificationName:kImageCapturedSuccessfully object:nil];
}];
}
You need to set the videoConnection's videoOrientation property based on the orientation of the device. Do this in captureStillImage, after you have set the AVCaptureConnection.
UIDeviceOrientation deviceOrientation =
[[UIDevice currentDevice] orientation];
AVCaptureVideoOrientation avcaptureOrientation;
if ( deviceOrientation == UIDeviceOrientationLandscapeLeft )
avcaptureOrientation = AVCaptureVideoOrientationLandscapeRight;
else if ( deviceOrientation == UIDeviceOrientationLandscapeRight )
avcaptureOrientation = AVCaptureVideoOrientationLandscapeLeft;
[videoConnection setVideoOrientation:avcaptureOrientation];
Im using AVCaptureSession for taking pictures and store pictures to album. When i click the button it takes the snapshot and store to album. But when i use landscape mode, then click the button it stores landscape mode image. When preview the image it is in portrait mode.
code:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[self setCaptureSession:[[AVCaptureSession alloc] init]];
[self addVideoInputFrontCamera:NO]; // set to YES for Front Camera, No for Back camera
[self addStillImageOutput];
[self setPreviewLayer:[[AVCaptureVideoPreviewLayer alloc] initWithSession:[self captureSession]] ];
// UIView *newView = [[UIView alloc] initWithFrame:self.view.bounds];
// [newView.layer addSublayer: self.previewLayer];
// [self.view addSubview: newView];
//previewLayer.frame=self.previewLayer.bounds;
[[self previewLayer] setVideoGravity:AVLayerVideoGravityResizeAspectFill];
// [[self previewLayer] setVideoGravity:AVLayerVideoGravityResize];
// self.previewLayer.orientation = AVCaptureVideoOrientationPortrait;
CGRect layerRect = [[[self view] layer] bounds];
[[self previewLayer]setBounds:layerRect];
[[self previewLayer] setPosition:CGPointMake(CGRectGetMidX(layerRect),CGRectGetMidY(layerRect))];
[[[self view] layer] addSublayer:[self previewLayer]];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(saveImageToPhotoAlbum) name:kImageCapturedSuccessfully object:nil];
[[self captureSession] startRunning];
camera=[UIButton buttonWithType:UIButtonTypeCustom];
[camera setImage:[UIImage imageNamed:#"button.png"] forState:UIControlStateNormal];
[camera setFrame:CGRectMake(150, 10, 40, 30)];
[camera addTarget:self action:#selector(takephoto:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:camera];
}
capture snapshot:
- (void)takephoto:(id)sender
{
[self captureStillImage];
}
- (void)captureStillImage
{
AVCaptureConnection *videoConnection = nil;
for (AVCaptureConnection *connection in [[self stillImageOutput] connections]) {
for (AVCaptureInputPort *port in [connection inputPorts]) {
if ([[port mediaType] isEqual:AVMediaTypeVideo]) {
videoConnection = connection;
break;
}
}
if (videoConnection) {
break;
}
}
NSLog(#"about to request a capture from: %#", [self stillImageOutput]);
[[self stillImageOutput] captureStillImageAsynchronouslyFromConnection:videoConnection
completionHandler:^(CMSampleBufferRef imageSampleBuffer, NSError *error) {
CFDictionaryRef exifAttachments = CMGetAttachment(imageSampleBuffer, kCGImagePropertyExifDictionary, NULL);
if (exifAttachments) {
NSLog(#"attachements: %#", exifAttachments);
} else {
NSLog(#"no attachments");
}
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];
UIImage *image = [[UIImage alloc] initWithData:imageData];
[self setStillImage:image];
// [image release];
[[NSNotificationCenter defaultCenter] postNotificationName:kImageCapturedSuccessfully object:nil];
}];
}
I'm using self.previewLayer.orientation = UIInterfaceOrientationLandscapeLeft; for landscape mode
In addition to previewLayer orientation you should set the videoOrientation for correcting this issue.
AVCaptureConnection *videoConnection = nil;
for (AVCaptureConnection *connection in [[self stillImageOutput] connections]) {
for (AVCaptureInputPort *port in [connection inputPorts]) {
if ([[port mediaType] isEqual:AVMediaTypeVideo]) {
videoConnection = connection;
break;
}
}
if (videoConnection) {
break;
}
}
after this
[videoConnection setVideoOrientation:AVCaptureVideoOrientationLandscapeLeft];
set the orientation by checking weather app in landscape or portrait mode..
I am trying to get the size of an image after it is downloaded using setImageFromURL:
UIImageView *img = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
[UIImageView setDefaultEngine:appDelegate.imageCache];
[img setImageFromURL:[NSURL URLWithString:#"http://testurl.com/testimg.jpg"]];
//img.frame = CGRectMake (0, 0, img.image.size.width, img.image.size.height);
[self.view addSubview:img];
I'm using MKNetworkKit -- is there a way to add a completion handler to the setImageFromURL method?
You can apply your own completion block
Few comments, please use Grand Central Dispatch to improve code efficiency and multi-core utilization for this kind of situations.
Example:
- (void) setImageFromUrl:(NSString*)urlString {
[self setImageFromUrl:urlString completion:NULL];
}
- (void) setImageFromUrl:(NSString*)urlString
completion:(void (^)(void))completion {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(#"Starting: %#", urlString);
UIImage *avatarImage = nil;
NSURL *url = [NSURL URLWithString:urlString];
NSData *responseData = [NSData dataWithContentsOfURL:url];
avatarImage = [UIImage imageWithData:responseData];
NSLog(#"Finishing: %#", urlString);
if (avatarImage) {
dispatch_async(dispatch_get_main_queue(), ^{
self.image = avatarImage;
//Assign the image to ur ImageView.
//get the image frame from ur ImageView.frame
});
dispatch_async(dispatch_get_main_queue(), completion);
}
else {
NSLog(#"-- impossible download: %#", urlString);
}
});
}
For more details , please visit iOS GCD magic
I was able to do it by adding this line:
self.frame = CGRectMake(0, 0, fetchedImage.size.width, fetchedImage.size.height);
to UIImageView+MKNetworkKitAdditions.m:
if(imageCacheEngine) {
self.imageFetchOperation = [imageCacheEngine imageAtURL:url
size:self.frame.size
completionHandler:^(UIImage *fetchedImage, NSURL *url, BOOL isInCache) {
self.frame = CGRectMake(0, 0, fetchedImage.size.width, fetchedImage.size.height);
[UIView transitionWithView:self.superview
duration:isInCache?kFromCacheAnimationDuration:kFreshLoadAnimationDuration
options:UIViewAnimationOptionTransitionCrossDissolve | UIViewAnimationOptionAllowUserInteraction
animations:^{
self.image = fetchedImage;
} completion:nil];
//[[NSNotificationCenter defaultCenter] postNotificationName:KW_IMAGE_LOADED object:nil];
} errorHandler:^(MKNetworkOperation *completedOperation, NSError *error) {
DLog(#"%#", error);
}];
} else {
DLog(#"No default engine found and imageCacheEngine parameter is null")
}
I need to take overlay image without setting drawInRect. When i set drawInRect it gives output of setting size. I need to take picture with new size without using following code.
- (void)captureStillImageWithOverlay:(UIImage*)overlay
{
AVCaptureConnection *videoConnection = nil;
for (AVCaptureConnection *connection in [[self stillImageOutput] connections]) {
for (AVCaptureInputPort *port in [connection inputPorts]) {
if ([[port mediaType] isEqual:AVMediaTypeVideo]) {
videoConnection = connection;
break;
}
}
if (videoConnection) {
break;
}
}
NSLog(#"about to request a capture from: %#", [self stillImageOutput]);
[[self stillImageOutput] captureStillImageAsynchronouslyFromConnection:videoConnection
completionHandler:^(CMSampleBufferRef imageSampleBuffer, NSError *error) {
CFDictionaryRef exifAttachments = CMGetAttachment(imageSampleBuffer, kCGImagePropertyExifDictionary, NULL);
if (exifAttachments) {
NSLog(#"attachements: %#", exifAttachments);
} else {
NSLog(#"no attachments");
}
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];
UIImage *image = [[UIImage alloc] initWithData:imageData];
CGSize imageSize = [image size];
CGSize overlaySize = [overlay size];
UIGraphicsBeginImageContext(imageSize);
[image drawInRect:CGRectMake(0, 0, imageSize.width, imageSize.height)];
CGFloat xScaleFactor = imageSize.width / 320;
CGFloat yScaleFactor = imageSize.height / 480;
[overlay drawInRect:CGRectMake(30 * xScaleFactor, 100 * yScaleFactor, overlaySize.width * xScaleFactor, overlaySize.height * yScaleFactor)]; // rect used in AROverlayViewController was (30,100,260,200)
// [overlay drawInRect:CGRectMake(30 * xScaleFactor, 100 * yScaleFactor, overlaySize.width * xScaleFactor, overlaySize.width* yScaleFactor)];
UIImage *combinedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// NSData * data = UIImagePNGRepresentation(image);
// [data writeToFile:#"foo.png" atomically:YES];
[self setStillImage:combinedImage];
[image release];
[[NSNotificationCenter defaultCenter] postNotificationName:kImageCapturedSuccessfully object:nil];
}];
}
Try this code :
UIGraphicsBeginImageContext(self.view.bounds.size);
// retrieve the current graphics context
CGContextRef context = UIGraphicsGetCurrentContext();
// render view into context
[self.view.layer renderInContext:context];
// create image from context
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
image=[self cropImage:image];
UIGraphicsEndImageContext();
- (UIImage *)cropImage:(UIImage *)oldImage
{
CGSize imageSize = oldImage.size;
UIGraphicsBeginImageContextWithOptions(CGSizeMake( imageSize.width,imageSize.height - 150),NO,0.);
[oldImage drawAtPoint:CGPointMake( 0, -80) blendMode:kCGBlendModeCopy alpha:1.];
UIImage *croppedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return croppedImage;
}
I want to take picture with overlay image.
code:
- (void)addStillImageOutput
{
// NSLog(#"You capture image");
[self setStillImageOutput:[[[AVCaptureStillImageOutput alloc] init] autorelease]];
NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys:AVVideoCodecJPEG,AVVideoCodecKey,nil];
[[self stillImageOutput] setOutputSettings:outputSettings];
AVCaptureConnection *videoConnection = nil;
for (AVCaptureConnection *connection in [[self stillImageOutput] connections]) {
for (AVCaptureInputPort *port in [connection inputPorts]) {
if ([[port mediaType] isEqual:AVMediaTypeVideo] ) {
videoConnection = connection;
break;
}
}
if (videoConnection) {
break;
}
}
[[self captureSession] addOutput:[self stillImageOutput]];
}
- (void)captureStillImage
{
AVCaptureConnection *videoConnection = nil;
for (AVCaptureConnection *connection in [[self stillImageOutput] connections]) {
for (AVCaptureInputPort *port in [connection inputPorts]) {
if ([[port mediaType] isEqual:AVMediaTypeVideo]) {
videoConnection = connection;
break;
}
}
if (videoConnection) {
break;
}
}
NSLog(#"about to request a capture from: %#", [self stillImageOutput]);
[[self stillImageOutput] captureStillImageAsynchronouslyFromConnection:videoConnection
completionHandler:^(CMSampleBufferRef imageSampleBuffer, NSError *error) {
CFDictionaryRef exifAttachments = CMGetAttachment(imageSampleBuffer, kCGImagePropertyExifDictionary, NULL);
if (exifAttachments) {
NSLog(#"attachements: %#", exifAttachments);
} else {
NSLog(#"no attachments");
}
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];
UIImage *image = [[UIImage alloc] initWithData:imageData];
[self setStillImage:image];
[image release];
[[NSNotificationCenter defaultCenter] postNotificationName:kImageCapturedSuccessfully object:nil];
}];
}
OverlayImage:
-(void)ButtonPressed1{
UIImageView *overlayImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"sof.png"]];
[overlayImageView setFrame:CGRectMake(30, 100, 260, 200)];
[[self view] addSubview:overlayImageView];
[overlayImageView release];
}
captureStillImageAsynchronouslyFromConnection captures only data from connection (AVCaptureConnection) and the additional images are not in connection. They are in the view.
So, to "generate" an image with all elements (picture and overlay), you must have to do something like this:
UIGraphicsBeginImageContext(stillImage.size);
[stillImage drawInRect:CGRectMake(0, 0, picture.size.width, picture.size.height)];
[overlayImageView drawInRect:CGRectMake(overlayImageView.frame.origin.x, overlayImageView.frame.origin.y, overlayImageView.frame.size.width, overlayImageView.frame.size.height)];
UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
This code is considering that picture size is equal to screen size. If picture size is different, you have to calculate the coordinates to place the overlay in the drawRect method. Sorry for bad english.