У меня есть небольшое приложение дополненной реальности, которое я разрабатываю, и хотел бы знать, как сохранить скриншот того, что пользователь видит с нажатием кнопки или таймера.iPhone занимает увеличенную реальность скриншот с AVCaptureVideoPreviewLayer
Приложение работает, накладывая прямую трансляцию камеры над другим UIView. Я могу сохранить скриншоты с помощью кнопки питания + кнопка «домой», они сохраняются в кадре камеры. Однако Apple не будет отображать AVCaptureVideoPreviewLayer, даже если я попрошу окно сохранить себя. Он создаст прозрачную часть холста, где находится слой предварительного просмотра.
Каким образом можно использовать приложение дополненной реальности для сохранения скриншотов, в том числе прозрачности и подсмотров?
//displaying a live preview on one of the views
-(void)startCapture
{
captureSession = [[AVCaptureSession alloc] init];
AVCaptureDevice *audioCaptureDevice = nil;
// AVCaptureDevice *audioCaptureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
NSArray *videoDevices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
for (AVCaptureDevice *device in videoDevices) {
if(useFrontCamera){
if (device.position == AVCaptureDevicePositionFront) {
//FRONT-FACING CAMERA EXISTS
audioCaptureDevice = device;
break;
}
}else{
if (device.position == AVCaptureDevicePositionBack) {
//Rear-FACING CAMERA EXISTS
audioCaptureDevice = device;
break;
}
}
}
NSError *error = nil;
AVCaptureDeviceInput *audioInput = [AVCaptureDeviceInput deviceInputWithDevice:audioCaptureDevice error:&error];
if (audioInput) {
[captureSession addInput:audioInput];
}
else {
// Handle the failure.
}
if([captureSession canAddOutput:captureOutput]){
captureOutput = [[AVCaptureVideoDataOutput alloc] init];
[captureOutput setAlwaysDiscardsLateVideoFrames:YES];
[captureOutput setSampleBufferDelegate:self queue:queue];
[captureOutput setVideoSettings:videoSettings];
dispatch_release(queue);
}else{
//handle failure
}
previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:captureSession];
UIView *aView = arOverlayView;
previewLayer.frame =CGRectMake(0,0, arOverlayView.frame.size.width,arOverlayView.frame.size.height); // Assume you want the preview layer to fill the view.
[aView.layer addSublayer:previewLayer];
[captureSession startRunning];
}
//ask the entire window to draw itself in a graphics context. This call will not render
// AVCaptureVideoPreviewLayer. Он должен быть заменен представлением UIImageView или GL. // см следующий код для создания динамического обновления UIImageView - (Недействительными) saveScreenshot {
UIGraphicsBeginImageContext(appDelegate.window.bounds.size);
[appDelegate.window.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageWriteToSavedPhotosAlbum(screenshot, self,
@selector(image:didFinishSavingWithError:contextInfo:), nil);
}
//image saved to camera roll callback
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error
contextInfo:(void *)contextInfo
{
// Was there an error?
if (error != NULL)
{
// Show error message...
NSLog(@"save failed");
}
else // No errors
{
NSLog(@"save successful");
// Show message image successfully saved
}
}
Вот код для создания образа:
// вам нужно добавить контроллер представления в качестве делегировать на выходе камеры, чтобы получать уведомления о buffereed данных
-(void)activateCameraFeed
{
//this is the code responsible for capturing feed for still image processing
dispatch_queue_t queue = dispatch_queue_create("com.AugmentedRealityGlamour.ImageCaptureQueue", NULL);
captureOutput = [[AVCaptureVideoDataOutput alloc] init];
[captureOutput setAlwaysDiscardsLateVideoFrames:YES];
[captureOutput setSampleBufferDelegate:self queue:queue];
[captureOutput setVideoSettings:videoSettings];
dispatch_release(queue);
//......configure audio feed, add inputs and outputs
}
//buffer delegate callback
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
{
if (ignoreImageStream)
return;
[self performImageCaptureFrom:sampleBuffer];
}
Создание UIImage:
- (void) performImageCaptureFrom:(CMSampleBufferRef)sampleBuffer
{
CVImageBufferRef imageBuffer;
if (CMSampleBufferGetNumSamples(sampleBuffer) != 1)
return;
if (!CMSampleBufferIsValid(sampleBuffer))
return;
if (!CMSampleBufferDataIsReady(sampleBuffer))
return;
imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
if (CVPixelBufferGetPixelFormatType(imageBuffer) != kCVPixelFormatType_32BGRA)
return;
CVPixelBufferLockBaseAddress(imageBuffer,0);
uint8_t *baseAddress = (uint8_t *)CVPixelBufferGetBaseAddress(imageBuffer);
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
size_t width = CVPixelBufferGetWidth(imageBuffer);
size_t height = CVPixelBufferGetHeight(imageBuffer);
CGImageRef newImage = nil;
if (cameraDeviceSetting == CameraDeviceSetting640x480)
{
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef newContext = CGBitmapContextCreate(baseAddress, width, height, 8, bytesPerRow, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
newImage = CGBitmapContextCreateImage(newContext);
CGColorSpaceRelease(colorSpace);
CGContextRelease(newContext);
}
else
{
uint8_t *tempAddress = malloc(640 * 4 * 480);
memcpy(tempAddress, baseAddress, bytesPerRow * height);
baseAddress = tempAddress;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef newContext = CGBitmapContextCreate(baseAddress, width, height, 8, bytesPerRow, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst);
newImage = CGBitmapContextCreateImage(newContext);
CGContextRelease(newContext);
newContext = CGBitmapContextCreate(baseAddress, 640, 480, 8, 640*4, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
CGContextScaleCTM(newContext, (CGFloat)640/(CGFloat)width, (CGFloat)480/(CGFloat)height);
CGContextDrawImage(newContext, CGRectMake(0,0,640,480), newImage);
CGImageRelease(newImage);
newImage = CGBitmapContextCreateImage(newContext);
CGColorSpaceRelease(colorSpace);
CGContextRelease(newContext);
free(tempAddress);
}
if (newImage != nil)
{
//modified for iOS5.0 with ARC
tempImage = [[UIImage alloc] initWithCGImage:newImage scale:(CGFloat)1.0 orientation:cameraImageOrientation];
CGImageRelease(newImage);
//this call creates the illusion of a preview layer, while we are actively switching images created with this method
[self performSelectorOnMainThread:@selector(newCameraImageNotification:) withObject:tempImage waitUntilDone:YES];
}
CVPixelBufferUnlockBaseAddress(imageBuffer,0);
}
обновление интерфейса с UIView, который на самом деле может быть оказанной в графическом контексте:
- (void) newCameraImageNotification:(UIImage*)newImage
{
if (newImage == nil)
return;
[arOverlayView setImage:newImage];
//or do more advanced processing of the image
}
вы желая сделать снимок того, что на экране программно вместо кнопке домой/власти? Я все равно отправлю код :) –
Пожалуйста, проверьте: http://stackoverflow.com/questions/3397899/avcapturevideopreviewlayer-taking-a-snapshot/13576530#13576530. Надеюсь, что поможет! –