【问题标题】:iPhone 6+ (Wrong scale?)iPhone 6+(比例不对?)
【发布时间】:2016-04-07 07:01:19
【问题描述】:

我有一个 iOS 应用程序使用相机拍照。 它使用在屏幕上绘制的路径(CGPath)(例如矩形),并在该路径内拍摄照片。该应用仅支持纵向。

为此,我使用:AVCaptureSessionAVCaptureStillImageOutputAVCaptureDeviceAVCaptureVideoPreviewLayer (我想制作这种应用程序的开发人员都很熟悉)。

我的代码使用UIScreen.mainScreen().boundsUIScreen.mainScreen().scale 来适应各种设备并完成其工作。

一切正常(在 iPhone 5、iPhone 6 上),直到我在 iPhone 6+(运行 iOS 9.3.1)上尝试该应用程序并发现有问题。 拍摄的照片不再摆放在正确的位置。

我让某人试用了 iPhone 6+,通过发送适当的消息,我能够确认 (UIScreen.mainScreen().scale) 应该是:3.0。 我在项目中放置了适当尺寸的启动图像(640 × 960、640 × 1136、750 × 1334、1242 × 2208)。 那么可能是什么问题呢?

【问题讨论】:

  • 如果你有 git 我会看看 6+

标签: ios avcapturesession iphone-6-plus avcapturedevice uiscreen


【解决方案1】:

我在应用程序中使用下面的代码,它适用于 6+。

代码启动 AVCaptureSession,从设备的摄像头提取视频输入。

在执行此操作时,它会不断更新来自 captureOutput 委托函数的 runImage var。

当用户想要拍照时,会调用 takePhoto 方法。此方法创建一个临时 UIImageview 并将 runImage 输入其中。然后使用这个临时 UIImageView 将另一个名为 currentImage 的变量绘制到设备的比例。

在我的例子中,currentImage 是方形的,与 previewHolder 框架相匹配,但我想你可以制作任何你想要的东西。

声明这些:

AVCaptureDevice * device;
AVCaptureDeviceInput * input;
AVCaptureVideoDataOutput * output;
AVCaptureSession * session;
AVCaptureVideoPreviewLayer * preview;
AVCaptureConnection * connection;
UIImage * runImage;

加载扫描器:

-(void)loadScanner 
{

    device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];
    output = [AVCaptureVideoDataOutput new];
    session = [AVCaptureSession new];

    [session setSessionPreset:AVCaptureSessionPresetPhoto];
    [session addInput:input];
    [session addOutput:output];

    [output setSampleBufferDelegate:self queue:dispatch_get_main_queue()];
    [output setVideoSettings:[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:kCVPixelFormatType_32BGRA] forKey:(id)kCVPixelBufferPixelFormatTypeKey]];

    preview = [AVCaptureVideoPreviewLayer layerWithSession:session];
    preview.videoGravity = AVLayerVideoGravityResizeAspectFill;
    preview.frame = previewHolder.bounds;

    connection = preview.connection;
    [connection setVideoOrientation:AVCaptureVideoOrientationPortrait];
    [previewHolder.layer insertSublayer:preview atIndex:0];

}

正在进行的图像捕获,更新 runImage var。

-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection 
{

    runImage = [self imageForBuffer:sampleBuffer];

}

与上述有关。

-(UIImage *)imageForBuffer:(CMSampleBufferRef)sampleBuffer 
{

    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
    CVPixelBufferLockBaseAddress(imageBuffer, 0);
    void *baseAddress = CVPixelBufferGetBaseAddress(imageBuffer);
    size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
    size_t width = CVPixelBufferGetWidth(imageBuffer);
    size_t height = CVPixelBufferGetHeight(imageBuffer);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(baseAddress, width, height, 8, bytesPerRow, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
    CGImageRef quartzImage = CGBitmapContextCreateImage(context);
    CVPixelBufferUnlockBaseAddress(imageBuffer,0);
    CGContextRelease(context);
    CGColorSpaceRelease(colorSpace);
    UIImage *image = [UIImage imageWithCGImage:quartzImage];
    CGImageRelease(quartzImage);

    UIImage * rotated = [[UIImage alloc] initWithCGImage:image.CGImage scale:1.0 orientation:UIImageOrientationRight];

    return rotated;
}

拍照时:

-(void)takePhoto 
{

    UIImageView * temp = [UIImageView new];
    temp.frame = previewHolder.frame;
    temp.image = runImage;
    temp.contentMode = UIViewContentModeScaleAspectFill;
    temp.clipsToBounds = true;
    [self.view addSubview:temp];

    UIGraphicsBeginImageContextWithOptions(temp.bounds.size, NO, [UIScreen mainScreen].scale);
    [temp drawViewHierarchyInRect:temp.bounds afterScreenUpdates:YES];
    currentImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    [temp removeFromSuperview];

    //further code...

}

【讨论】:

  • 为什么你的代码是做什么的?请提供您的代码说明以及为什么它可以解决用户问题。
  • @Popeye 更新了进一步的解释;它是否对用户有帮助我不知道它会,但我没有看到任何 6+ 问题(如果它甚至是一个问题,我们不能肯定地说)。
  • 我正在查看您的代码。试着看看它和我的有什么不同。除了我在 Swift 中,我已经可以看到一些变化。你用AVCaptureVideoDataOutput,我用AVCaptureStillImageOutput;你用AVCaptureSessionPresetPhoto,我用AVCaptureSessionPresetHigh ..等等。我想这应该不是问题。另一方面,您使用的 AVLayerVideoGravityResizeAspectFillAVCaptureVideoOrientationPortrait 可能不会有所作为。对于imageForBuffer,我使用的是在这里找到的代码:developer.apple.com/library/ios/documentation/AudioVideo/ 我还需要进一步研究。
  • 我可能会隔离并上传我的一些相关代码。尽管正如我在帖子中所写,由于它适用于其他手机,但我强烈怀疑 iPhone 6+ 上 UIScreen.mainScreen().scale 返回的值是问题所在,而不是我的代码。
  • 是的,如果它被隔离到一种设备类型,代码可能是好的,虽然与 iPhone6+ 下采样无关:paintcodeapp.com/news/iphone-6-screens-demystified
【解决方案2】:

如果其他人有同样的问题。以下是我遇到问题的原因:

我正在命名一个文件:xyz@2x.png。

当 UIScreen.mainScreen().scale == 3.0(iPhone 6+ 的情况) 它必须命名为:xyz@3x.png。

【讨论】:

  • 您不必为图像使用 2x 和 3x 扩展名——我从不使用它们,这太麻烦了。只需抓取最大的图像并让设备为您缩小它,例如bigImage.png 放入带有 contentMode AspectFill 的 UIImageView。减少头痛。
  • 我不知道是否必须。但我所知道的是,当我在所有情况下命名文件 x.@2x.png 时,都有一个错误,当我根据 UIScreen.mainScreen().scale 的值命名时,它可以工作。在所有可能的情况下,让设备扩展并不是您想要的。同样,您不一定要选择最大的几张图像。无论如何,如果你说,你可以避免使用多个扩展,那是最好的。
猜你喜欢
  • 2015-03-31
  • 1970-01-01
  • 1970-01-01
  • 2015-04-27
  • 2015-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-24
相关资源
最近更新 更多