[Résolu] Resize image sans la dupliquer

busterTheobusterTheo Membre
décembre 2016 modifié dans API UIKit #1

Bonjour,


en travaillant en tant que débutant sur Instruments, et en ayant eu des réponses passionnantes sur ce forum, je cherche à  résoudre ce problème :


Suite à  ce code que j'ai adapté (si peu !!!) d'après tous les codes du web sur ce sujet que j'ai pu trouver :



func scaledImageWithImage(image: UIImage, size: CGSize) -> UIImage {
let scale: CGFloat = max(size.width/image.size.width, size.height/image.size.height)
let width: CGFloat = image.size.width * scale
let height: CGFloat = image.size.height * scale
let imageRect: CGRect = CGRectMake((size.width-width)/2.0, (size.height-height)/2.0, width, height)

UIGraphicsBeginImageContextWithOptions(size, false, 0)
image.drawInRect(imageRect)
let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

return newImage
}

J'ai eu cette réponse qui m'interpelle :



 


 


Dans l'exemple de l'image, c'est normal: tu prends une image, et tu en crées une deuxième, donc il y a un moment où tu as les deux en mémoire.

Et donc, j'ai cherché partout, même sur ce forum, et je ne trouve rien qui me dirait comment faire pour éviter ce problème.


 


Si quelqu'un a une idée, ce serait super. Merci d'avance.


 


Réponses

  • DrakenDraken Membre
    mars 2016 modifié #2

    Tu ne peux pas éviter le problème. Mais tu peux détruire la première image après conversion pour récupérer la mémoire.



    let image1:UIImage? = loadQuelqueChose("...")
    let image2 = scaledImageWithImage(image1, size)
    image1 = nil



    Ou plus simplement :



    let image1:UIImage? = loadQuelqueChose("...")
    image1 = scaledImageWithImage(image1, size)



    Comme ça, tu évites de faire la destruction à  la main (jamais une bonne idée). Swift vas effacer automatiquement l'ancienne version de l'image contenu dans la variable image1.

  • MalaMala Membre, Modérateur

    Où est le problème? A un moment, il faut bien que tu utilises ton image d'origine pour la recopier en version réduite dans ton image d'arrivée fraichement créée...


  • busterTheobusterTheo Membre
    mars 2016 modifié #4

    Ah Draken, je crois avoir compris le truc. Si c'est ça, c'est génial.


    C'est d'une logique imparable, et chui pas malin.


     


    D'ailleurs (dans ton code), ce serait plutôt un var que un let. Non ? Mais bon... Pas important.


     


    En gros, si j'ai bien compris, je transformerai ce code :



    let frontalPhoto = singlePatient.photoFrontal
    let pathFull:String = documentsDir + "/" + frontalPhoto
    if let zeImage:UIImage = UIImage(contentsOfFile: pathFull as String) {
    imageViewEtapes.image = zeImage
    imageViewEtapes.image = scaledImageWithImage(imageViewEtapes.image!, size: TaillePhotos)
    }

    En ça :



    let frontalPhoto = singlePatient.photoFrontal
    let pathFull:String = documentsDir + "/" + frontalPhoto
    var zeImage: UIImage = UIImage(contentsOfFile: pathFull as String)!
    zeImage = scaledImageWithImage(zeImage, size: TaillePhotos)
    imageViewEtapes.image = zeImage

    Et pour prouver que je comprend toujours pas complètement les histoire de poneys de Aligator, Xcode (the newbie as Aligator said), me dit de mettre un "!" là  :



    UIImage(contentsOfFile: pathFull as String)! 

    :D


     


    Merci de me confirmer...


  • Ta routine de resize est trop compliqué. Tu peux créer le rectangle de destination directement à  partir du paramètre size.




    func scaledImageWithImage(image: UIImage, size: CGSize) -> UIImage {
    let imageRect = CGRect(origin: CGPoint(x: 0,y: 0), size: size)
    UIGraphicsBeginImageContextWithOptions(size, false, 0)
    image.drawInRect(imageRect)
    let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return newImage
    }


    C'est mieux, mais pas encore dans l'esprit Swift. On tue encore des poneys, là .


    Une autre version, avec une extension de UIImage :



    extension UIImage {
    func resize(size:CGSize) -> UIImage? {
    let imageRect = CGRect(origin: CGPoint(x: 0,y: 0), size: size)
    UIGraphicsBeginImageContextWithOptions(size, false, 0)
    self.drawInRect(imageRect)
    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return newImage
    }
    }


    Utilisation :



    var image1 = UIImage(named: "image01")
    let size = CGSize(width: 200,height: 200)
    image1 = image1?.resize(size)

  • busterTheobusterTheo Membre
    mars 2016 modifié #6

    Ouah, faut que j'aille cherché mon cerveau qui s'est caché dans les limbes du code.  :D


     


    Merci beaucoup.


  • Hummm, ça c'est beau (avec l'extension, évidemment) :



    image1 = image1?.resize(size)

    Plutôt que :



    image1 = scaledImageWithImage(image1, size: TaillePhotos)

    La grande classe. J'adore.


     


     


    Par contre je comprend pas où tu tues des poneys, dans ton premier code ?

  • busterTheobusterTheo Membre
    mars 2016 modifié #8

    Et, quand tu dis :



     


     


    Ta routine de resize est trop compliqué

     


    je suis super d'accord avec toi, mais le problème est que la photo à  resizer est une photo que l'utilisateur de l'appli chargera à  partir de l'appareil photo de son ipad, ou de droppBox, ou de son album, et donc je ne peux pas savoir si elle est horizontale ou verticale.


     


    C'est pourquoi, j'ai besoin de cela :



    let scale: CGFloat = max(size.width/image.size.width, size.height/image.size.height)

    Donc, ... ?


  • DrakenDraken Membre
    mars 2016 modifié #9


    Ah Draken, je crois avoir compris le truc. Si c'est ça, c'est génial.


    C'est d'une logique imparable, et chui pas malin.


     


    D'ailleurs (dans ton code), ce serait plutôt un var que un let. Non ? Mais bon... Pas important.


     




    Tu as raison, j'ai tapé le code de mémoire. Je met toujours let pour la création des objets, laissant à  Xcode la tâche de me prévenir quand il faut mettre un var.


     


     



     


    Et pour prouver que je comprend toujours pas complètement les histoire de poneys de Aligator, Xcode (the newbie as Aligator said), me dit de mettre un "!" là  :


    UIImage(contentsOfFile: pathFull as String)! 

     


    Oo le beau cadavre de poneys !



    var zeImage: UIImage = UIImage(contentsOfFile: pathFull as String)!

    Le chargement d'une image peut échouer, donc UIImage(contentsOfFile:) retourne une UImage? (une UIImage optionnelle).


     


    Mais toi, tu obliges le compilateur à  utiliser une UImage non optionnelle en forçant son type. Xcode a donc besoin de convertir l'image optionnelle en non optionnelle en ajoutant un !. Pas bien ..


     


    Il faut écrire : 



    var zeImage: UIImage? = UIImage(contentsOfFile: pathFull as String)

    pour ne pas forcer une conversion inutile et dangereuse. Si le chargement de l'image échoue pour une raison ou une autre, UIImage(contentsOfFile) var retourner nil. Ton application vas planter en tentant de convertir le nil en UIImage.


     


     


    Plus simple encore :



    var zeImage = UIImage(contentsOfFile: pathFull)


    UIImage retournant une UIImage?, Xcode sait que zeImage doit être de type UIImage? sans ajouter de déclarations inutiles.

  • Mort de rire, j'en ai mal aux cheveux.


    Mais bon, je commence à  peine à  comprendre.


     


    Ok, pas de forçage de type.


     


    Mais xcode m'oblige à  présent à  mettre encore un "!", et ce coup-ci au zeImage, dans l'appel du scaledWithImage :



    var zeImage = UIImage(contentsOfFile: pathFull as String)
    zeImage = scaledImageWithImage(zeImage!, size: TaillePhotos)

    Oups, un poney peut-il en cacher un autre ?  :D  :o   :D



  • Par contre je comprend pas où tu tues des poneys, dans ton premier code ?




    En retournant un UIImage et non un UIImage?. L'opération de resize peut échouer pour une raison quelconque.


     


     



     


    je suis super d'accord avec toi, mais le problème est que la photo à  resizer est une photo que l'utilisateur de l'appli chargera à  partir de l'appareil photo de son ipad, ou de droppBox, ou de son album, et donc je ne peux pas savoir si elle est horizontale ou verticale.


     


    C'est pourquoi, j'ai besoin de cela :


    let scale: CGFloat = max(size.width/image.size.width, size.height/image.size.height)

    Donc, ... ?


     


    Sorry, je n'avais pas compris le truc. Je t'ai écrit une fonction générique "basique", sans penser à  ce problème d'orientation, que je n'ai jamais rencontré. 


  •  


     


    Sorry, je n'avais pas compris le truc. Je t'ai écrit une fonction générique "basique", sans penser à  ce problème d'orientation, que je n'ai jamais rencontré. 

     


    T'inquiètes... À moi de l'adapter. Je devrais m'en sortir. Merci.




  • Mort de rire, j'en ai mal aux cheveux.


    Mais bon, je commence à  peine à  comprendre.


     


    Ok, pas de forçage de type.


     


    Mais xcode m'oblige à  présent à  mettre encore un "!", et ce coup-ci au zeImage, dans l'appel du scaledWithImage :



    var zeImage = UIImage(contentsOfFile: pathFull as String)
    zeImage = scaledImageWithImage(zeImage!, size: TaillePhotos)

    Oups, un poney peut-il en cacher un autre ?  :D  :o   :D




    C'est parce que scaledImageWithImage() demande une UIImage non optionnelle en entrée. Tu pourrais en faire une nouvelle version demandant une UIImage? et retournant une UIImage?, pour être dans l'esprit Swift. J'avais commencé à  le faire, puis j'ai préféré écrire une extension pour être encore plus Swifty.

  • CéroceCéroce Membre, Modérateur
    mars 2016 modifié #14
    Je te conseille tout de même d'utiliser le code d'Aligator, par exemple:
    https://github.com/AliSoftware/UIImage-Resize

    Parce qu'il y a un truc que tu ne gères pas, ce sont les rotations "virtuelles" EXIF. En gros, les images sont orientées telles que prises par le capteur photo. Il y a un attribut dans le fichier qui indique l'orientation réelle.

    ça pose un vrai problème quand tu prends des images dans l'album photo ou avec la caméra. Auquel cas lorsque la photo a été prise en orientation "portrait", elle se retrouve tournée de ±90° ou 180°. Il faut le gérer lors du redimensionnement.
  • Très instructif ce fil !


     


    Et pour les poneys je viens de comprendre à  la lecture du blog d'AliGator...


     


    Faut suivre !



  • busterTheobusterTheo Membre
    mars 2016 modifié #16

    Ouaaah, merci. Je regarde tout ça, et reviens bientôt au bar.


     


    Ah c'est de l'objectiveC, va fallloir que je fasse marcher mes méninges à  400%...


  • CéroceCéroce Membre, Modérateur
    Non, tu intègres le code dans ton projet avec Cocoapods, et c'est tout.
  • ok merci pour l'info


Connectez-vous ou Inscrivez-vous pour répondre.