web-dev-qa-db-fra.com

Comment obtenir la superposition personnalisée de la caméra UIImagePicker en plein écran sous iOS 7?

Je suis intéressé par l’utilisation d’une superposition personnalisée pour la UIImagePickerController pour les commandes de l’appareil photo prenant tout l’écran, très semblable à ce que fait l’application Caméra par défaut lorsqu’elle est basculée sur la fonction vidéo. 

J'ai référencé plusieurs questions ici sur SO sur ce sujet, en particulier celui-ci one , ainsi que l'exemple Apple sur l'utilisation d'un calque personnalisé pour UIImagePickerController, mais aucun d'entre eux n'a réussi à obtenir un résultat plein écran réussi avec iOS 7.

Jusqu'à présent, voici à quoi ressemble l'interface utilisateur de l'appareil photo avec la superposition personnalisée (sans boutons):

enter image description here

Notez qu'il y a une barre noire au bas de l'écran. J'ai remarqué que je pourrais obtenir la barre noire supprimée si je change la cameraAspectRatio en 1, mais cela déforme le zoom de la caméra car il a alors une vue très agrandie. Existe-t-il un moyen de passer en plein écran sans déformer excessivement le zoom (je comprends qu'un petit peu est nécessaire) et de supprimer également la barre noire? 

Voici mon code qui configure la superposition personnalisée:

{
        self.imagePickerController.showsCameraControls = NO;

        [[NSBundle mainBundle] loadNibNamed:@"overlayView" owner:self options:nil];
        self.overlayView.frame = self.imagePickerController.cameraOverlayView.frame;
        self.imagePickerController.cameraOverlayView = self.overlayView;
        self.overlayView = nil;

        // Device's screen size (ignoring rotation intentionally):
        CGSize screenSize = [[UIScreen mainScreen] bounds].size;


        float cameraAspectRatio = 4.0 / 3.0; //! Note: 4.0 and 4.0 works
        float imageWidth = floorf(screenSize.width * cameraAspectRatio);
        float scale = ceilf((screenSize.height / imageWidth) * 10.0) / 10.0;

        self.imagePickerController.cameraViewTransform = CGAffineTransformMakeScale(scale, scale);

    }

Mettre à jour:

Un problème supplémentaire que j'ai remarqué est que l'image affichée dans l'aperçu de l'appareil photo est toujours plus petite et contient moins de détails que l'image enregistrée avec la méthode [self.imagePickerController takePicture]. Pour illustrer:

Voici à quoi ressemble le clavier dans l'aperçu de l'appareil photo avec la barre noire ci-dessous (désolé, il est un peu fragile):

enter image description here

Cependant, notez que l'image capturée dans le panneau d'aperçu contient beaucoup plus de détails, comme indiqué ici, en particulier vers le haut, ainsi que vers la gauche et la droite.

enter image description here

Ma question est la suivante: comment pourrais-je définir l'aperçu de mon appareil photo de sorte que ce que l'utilisateur voit dans l'aperçu soit exactement l'image qu'il va capturer et puisse lui être montré par la suite? Merci!

Mise à jour 2

Voici le code complet dans viewDidLoad qui configure les contrôles de la caméra.

- (void)viewDidLoad
{
    [super viewDidLoad];

    //Appearance configuration
    self.navigationItem.hidesBackButton = YES;

    //UIImagePickerController initialization and setup
    self.imagePickerController = [[UIImagePickerController alloc] init];
    self.imagePickerController.delegate = self;
    self.imagePickerController.allowsEditing = NO;
    if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]){
        self.imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera; //if there is a camera avaliable
    } else {
        self.imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;//otherwise go to the folder
    }
    self.imagePickerController.mediaTypes = [[NSArray alloc] initWithObjects: (NSString *) kUTTypeImage, nil];
    if (self.imagePickerController.sourceType == UIImagePickerControllerSourceTypeCamera)
    {
        self.imagePickerController.showsCameraControls = NO;

        [[NSBundle mainBundle] loadNibNamed:@"overlayView" owner:self options:nil];
        self.overlayView.frame = self.imagePickerController.cameraOverlayView.frame;
        self.imagePickerController.cameraOverlayView = self.overlayView;
        self.overlayView = nil;

        // Device's screen size (ignoring rotation intentionally):
        CGSize screenSize = [[UIScreen mainScreen] bounds].size;

        int heightOffset = 0;

        if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0"))
        {
            heightOffset = 120; //whole screen :)
        }

        float cameraAspectRatio = 4.0 / 3.0; //! Note: 4.0 and 4.0 works
        float imageWidth = floorf(screenSize.width * cameraAspectRatio);
        float scale = ceilf(((screenSize.height + heightOffset) / imageWidth) * 10.0) / 10.0;

        self.imagePickerController.cameraViewTransform = CGAffineTransformMakeScale(scale, scale);

    }
}

Et dans viewWillAppear, j'appelle la vue sélecteur d'images:

BOOL modalPresent = (BOOL)(self.presentedViewController);
    //Present the Camera UIImagePicker if no image is taken
    if (!appDelegate.imageStorageDictionary[@"picture1"]){
        if (modalPresent == NO){ //checks if the UIImagePickerController is modally active
            [self presentViewController:self.imagePickerController animated:NO completion:nil];
        }
    }
13
daspianist

Après de nombreuses tentatives, c’est ce qui a bien fonctionné pour moi, grâce aux suggestions des autres Les faits suivants ont été très utiles à connaître et à garder à l'esprit:

La résolution de l'appareil photo points est 426 * 320 . Pour que la taille de l'aperçu de l'appareil photo soit étendue à la hauteur de l'écran du téléphone de 568, vous devez la multiplier par 1,3333 si vous utilisez CGAffineTransformScale.

Notez que les éléments ci-dessous sont codés en dur avec différents nombres en fonction de la résolution d'écran de l'iPhone 5 en points. Ils pourraient être améliorés en utilisant des objets tels que screen.height, screen.width et d'autres variables pour le rendre également applicable aux dimensions de l'iPhone 4/4.

    self.imagePickerController.showsCameraControls = NO;

    [[NSBundle mainBundle] loadNibNamed:@"overlayView" owner:self options:nil];
    self.overlayView.frame = self.imagePickerController.cameraOverlayView.frame;
    self.imagePickerController.cameraOverlayView = self.overlayView;
    self.overlayView = nil;

    //For iphone 5+
    //Camera is 426 * 320. Screen height is 568.  Multiply by 1.333 in 5 inch to fill vertical
    CGAffineTransform translate = CGAffineTransformMakeTranslation(0.0, 71.0); //This slots the preview exactly in the middle of the screen by moving it down 71 points
    self.imagePickerController.cameraViewTransform = translate;

    CGAffineTransform scale = CGAffineTransformScale(translate, 1.333333, 1.333333);
    self.imagePickerController.cameraViewTransform = scale;
26
daspianist

En rapide

var picker: UIImagePickerController = UIImagePickerController();

picker.sourceType = UIImagePickerControllerSourceType.Camera;

picker.showsCameraControls = false;

var screenBounds: CGSize = UIScreen.mainScreen().bounds.size;

var scale = screenBounds.height / screenBounds.width;

picker.cameraViewTransform = CGAffineTransformScale(picker.cameraViewTransform, scale, scale);

9
Vikramaditya

Assurez-vous de prendre en compte le changement de barre d’état 20px dans iOS7. Si vous faites face à un écran noir de 20 pixels au bas de l'écran, ce sera votre problème. Vous pouvez vérifier que l'application fonctionne sous ios7 ou non avec l'un de ces préprocesseurs. 

#define SYSTEM_VERSION_EQUAL_TO(v)                  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame)
#define SYSTEM_VERSION_GREATER_THAN(v)              ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending)
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN(v)                 ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v)     ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending)

Et vous pouvez apporter les modifications suivantes à votre code et voir si cela fonctionne.

{
        self.imagePickerController.showsCameraControls = NO;

        [[NSBundle mainBundle] loadNibNamed:@"overlayView" owner:self options:nil];
        self.overlayView.frame = self.imagePickerController.cameraOverlayView.frame;
        self.imagePickerController.cameraOverlayView = self.overlayView;
        self.overlayView = nil;

        // Device's screen size (ignoring rotation intentionally):
        CGSize screenSize = [[UIScreen mainScreen] bounds].size;

        int heightOffset = 0;

        if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0"))
        {
            heightOffset = 20;
        }

        float cameraAspectRatio = 4.0 / 3.0; //! Note: 4.0 and 4.0 works
        float imageWidth = floorf(screenSize.width * cameraAspectRatio);
        float scale = ceilf(((screenSize.height + heightOffset) / imageWidth) * 10.0) / 10.0;

        self.imagePickerController.cameraViewTransform = CGAffineTransformMakeScale(scale, scale);

    }

S'il vous plaît laissez-moi savoir si cela fonctionne. Je ne l'ai pas codé pour tester.

2
Kamran Khan

Il existe une méthode plus simple pour obtenir votre écran plein écran au moins testé dans iOS 9.

let view    = ... your overlayView
let bounds  = UIScreen.mainScreen().bounds
view.center = CGPoint(x: bounds.midX, y: bounds.midY)
view.bounds = bounds
self.imagePicker.cameraOverlayView = view
1
Nicolas Manzini

Le format de l'écran étant différent du format 4/3 de l'appareil photo lui-même, vous devez (comme vous l'avez mentionné) recadrer légèrement les bords pour que l'image soit étendue vers le bas.

Pour ce faire, la largeur doit être suffisamment large pour que la hauteur puisse être en plein écran. Donc, la largeur et la hauteur de votre image doivent être:

float cameraAspectRatio = 4.0 / 3.0; //! Note: 4.0 and 4.0 works
float imageWidth = screenSize.height / cameraAspectRatio;

Vous voudrez probablement aussi que la vue présentant l'image de la caméra ait cette largeur qui s'étend des deux côtés de l'écran.

Essayez ce code pour conserver votre image résultante au format personnalisé. J'ai obtenu le résultat en utilisant une méthode personnalisée pour obtenir l'image résultante en taille personnalisée.

Créez d'abord IBOutlet pour UIImageview.

-(void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info
{
    NSString *mediaType = info[UIImagePickerControllerMediaType];
[self dismissViewControllerAnimated:YES completion:nil];


if ([mediaType isEqualToString:(NSString *)kUTTypeImage]) {
    OriginalImage=info[UIImagePickerControllerOriginalImage];
    image = info[UIImagePickerControllerOriginalImage];
//----------------------------------------
     imageview.image = image; //------------- additional method for custom image size
     self resizeImage];


//-----------------------------------------
        if (_newMedia)
            UIImageWriteToSavedPhotosAlbum(image,self,@selector(image:finishedSavingWithError:contextInfo:),nil);

}
else if ([mediaType isEqualToString:(NSString *)kUTTypeMovie])
{
    // Code here to support video if enabled
}

}

// ---- Redimensionne l'image d'origine à l'aide de la méthode personnalisée ----------------------

-(void)resizeImage
{
    UIImage *resizeImage = imageview.image;

    float width = 320;
    float height = 320;

    CGSize newSize = CGSizeMake(320,320);
    UIGraphicsBeginImageContextWithOptions(newSize,NO,0.0);
    CGRect rect = CGRectMake(0, 0, width, height);

    float widthRatio = resizeImage.size.width / width;
    float heightRatio = resizeImage.size.height / height;
    float divisor = widthRatio > heightRatio ? widthRatio : heightRatio;

    width = resizeImage.size.width / divisor;
    height = resizeImage.size.height / divisor;

    rect.size.width  = width;
    rect.size.height = height;

    //indent in case of width or height difference
    float offset = (width - height) / 2;
    if (offset > 0) {
        rect.Origin.y = offset;
    }
    else {
        rect.Origin.x = -offset;
    }

    [resizeImage drawInRect: rect];

    UIImage *smallImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

imageview.image = smallImage;
imageview.contentMode = UIViewContentModeScaleAspectFit;

}
0
svmrajesh

Essayez ce code, ça marche très bien pour moi

UIImagePickerController *cameraUI = [[UIImagePickerController alloc] init];
cameraUI.sourceType = UIImagePickerControllerSourceTypeCamera;
cameraUI.showsCameraControls = NO;

CGSize screenSize = [[UIScreen mainScreen] bounds].size;
float cameraAspectRatio = 4.0 / 3.0;
float imageHeight = floorf(screenSize.width * cameraAspectRatio);
float scale = screenSize.height / imageHeight;
float trans = (screenSize.height - imageHeight)/2;
CGAffineTransform translate = CGAffineTransformMakeTranslation(0.0, trans);
CGAffineTransform final = CGAffineTransformScale(translate, scale, scale);
cameraUI.cameraViewTransform = final
;
cameraUI.delegate = self;
[self presentViewController:cameraUI animated:YES completion:nil];

Ce code suppose que l'aspect de la zone d'aperçu de la caméra d'origine est 4: 3.

0
wzienrgo

Je ne sais pas pourquoi vous utilisez la taille de l'écran. Essayez juste ce code simple:

if ([UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypeCamera])

{

     UIImagePickerController *controller = [[UIImagePickerController alloc] init];
     controller.sourceType = UIImagePickerControllerSourceTypeCamera;
     controller.allowsEditing = NO;
     controller.mediaTypes = [UIImagePickerController availableMediaTypesForSourceType:
     UIImagePickerControllerSourceTypeCamera];
     controller.delegate = self;
     [self presentViewController:controller animated:NO completion:^{}];
}
0
Naeem Paracha

Pour résoudre un problème similaire, j'ai instancié un ViewController à partir du storyboard et utilisé la vue du contrôleur comme superposition de caméra .. Je ne sais pas si c'est ce que vous cherchez, mais j'ai utilisé le code suivant:

UIImagePickerController *globalPicker = [[UIImagePickerController alloc] init];
globalPicker.delegate = self;
globalPicker.sourceType = UIImagePickerControllerSourceTypeCamera;controller=[self.storyboard instantiateViewControllerWithIdentifier:@"myVC"];
overlayView = controller.view;
UIView *cameraView=[[UIView alloc] initWithFrame:self.view.bounds];
[cameraView addSubview:overlayView];
[globalPicker setCameraOverlayView:cameraView];
0
Nico.S