Core Data + iCloud - Optimisation de la taille des images

Bonsoir,

Je suis toujours sur mon application de cave à vin, basée sur l’utilisation de Core Data + CloudKit.

À chaque bouteille est associée une étiquette.
Je gère une vignette « thumbnail » de taille réduite (60 x 90) et une image de meilleure résolution que je transforme en image 600 x 900 avant de la stocker dans Core Data et iCloud. Lorsque l’utilisateur clique sur la vignette, l’image en résolution 600 x 900 s’affiche sur l’iPhone ou l’iPad.
Ces deux images sont stockées sous forme de Binary Data dans un objet Core Data « Etiquette ».

Pour 220 bouteilles (et donc 220 étiquettes), la taille des données sur mon iPhone fait 455 Mo (+ 1 Mo pour l’app elle-même).

Question: puis-je réduire fortement la taille de mon app sans réduire la qualité de ce que j’affiche à l’utilisateur quand il clique sur la vignette de l’étiquette ?

Pour information, le code utilisé pour traiter l’image sélectionnée par l’utilisateur:

 if let imageData = image.pngData() {
            if let fullSizeImage = resizedImage(with: imageData, for: CGSize(width: 600, height: 900)), let thumbnailUIImage = resizedImage(with: imageData, for: CGSize(width: 60, height: 90)) {
                let etiquette = Etiquette(context: context)
                etiquette.imageFullSize = fullSizeImage.pngData()
                etiquette.thumbnail = thumbnailUIImage.pngData()
                etiquette.bouteille = newItem
            }
        }
func resizedImage(with data: Data, for size: CGSize) -> UIImage? {
    let options: [CFString: Any] = [
        kCGImageSourceCreateThumbnailFromImageIfAbsent: true,
        kCGImageSourceCreateThumbnailWithTransform: true,
        kCGImageSourceShouldCacheImmediately: true,
        kCGImageSourceThumbnailMaxPixelSize: max(size.width, size.height)
    ]

    guard let imageSource = CGImageSourceCreateWithData(data as CFData, nil),
        let image = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options as CFDictionary)
    else {
        return nil
    }

    return UIImage(cgImage: image)
}

Cordialement,
Nicolas

As-tu essayé du .jpg plutôt que du png pour les grandes images ?

Édit : sinon j’avais fait des essais, il y a quelques années avec un format graphique très compact, dont le decompactage était géré en hard par le GPU de l’iPhone. Très efficace, même s’il fallait passer par un utilitaire un peu compliqué en ligne de commande, pour générer les fichiers graphiques. Je ne me souviens plus du nom, mais cela doit se retrouver dans la doc Apple.

Edit 2 : probablement les format HEIF/HEFC

Merci Draken,

Je vais voir ce que je trouve et faire des tests !

Rien que le fait d’utiliser du .jpg au lieu du .png vas te faire gagner une place folle …

Bonsoir,

En compressant en jpg, ça va effectivement beaucoup mieux !!!
Merci

// Extension pour redimensionner les images choisies par l'utilisateur
extension UIImage {
    
    enum JPEGSizeInKB: Int {
        case lowest  = 20
        case low     = 200
        case medium  = 500
        case high    = 700
        case highest = 1_000
    }
    
    func compressImageToData(with targetSizeInKB:JPEGSizeInKB) -> Data? {
        let minCompression:CGFloat = 0.1
        var compression:CGFloat = 1.0
        var imageData = self.jpegData(compressionQuality: compression)
        guard imageData != nil else { return nil }
        
        while (imageData!.count / 1024 > targetSizeInKB.rawValue) && (compression >= minCompression) {
            compression -= 0.1
            imageData = self.jpegData(compressionQuality: compression)
            print("taille de l'image \(imageData!.count)")
            guard imageData != nil else { return nil }
            
        }
        
        return imageData
    }
}

Tu utilises une compression .jpg en qualité maximale (1.0). Essaye une valeur plus faible, pour améliorer la compression. Il y a un équilibre à trouver entre facteur de compression et qualité graphique.

Edit : oups, j’avais juste lu le début du code !

Bonjour,

Petite question (désolé je ne vais pas aider à la résolution du problème). J’ai une apps similaire mais pas avec du vin mais des BD ou des livres (c’est moins fun :slight_smile:) . On insère un livre et il est possible d’uploader une vignette de la couverture de la BD soit à partir de l’APN de l’iPhone/iPad soit à partir de la bibliothèque de l’appareil.

Le tout est sauvegardé de la même façon que toi via Core Data et syncro dans CloudKit.

Comme l’appli est en swiftui, je passe par un picker (UIViewControllerRepresentable) pour sélectionner les images avant de les sauvegarder dans CoreData (type de donnée Binary).
le taux de compression est à 0.5 en jpg

Mon problème est en production : la synchronisation ne se fait pas d’un appareil à un autre et semble même bloquer complètement toute la syncro; ce qui fait que les appareils ne sont pas à jour entre eux.
je n’ai aucun problème en développement : les deux simulateurs se synchronisent parfaitement et quasi instantanément.

Du coup, je ne vois pas trop où peut être le problème… Si quelqu’un à une idée (erreur dans la migration du schéma CloudKit peut être?)…

Merci d’avance pour votre aide dans ma réflexion.

Bon we.

Benjamin

Bonjour benjamin512,

Je ne suis pas sûr de comprendre: le problème ne se produit que pour la synchro des images ? ou de manière plus générale ?

Deux suggestions pour essayer de t’aider:

  • tu devrais créer un nouveau sujet sur le forum
  • il faudra poster du code !

Cordialement,
Nicolas

Je vais ouvrir un nouveau post.
Mais globalement oui c’est les images qui ne se synchronisent pas.