Question

Comment puis-je économiser un NSImage comme un nouveau fichier (png, jpg, ...) dans un répertoire?

Était-ce utile?

La solution

Faites quelque chose comme ceci:

NSBitmapImageRep *imgRep = [[image representations] objectAtIndex: 0];
NSData *data = [imgRep representationUsingType: NSPNGFileType properties: nil];
[data writeToFile: @"/path/to/file.png" atomically: NO];

Autres conseils

Vous pouvez ajouter une catégorie à NSImage comme ceci

@interface NSImage(saveAsJpegWithName)
- (void) saveAsJpegWithName:(NSString*) fileName;
@end

@implementation NSImage(saveAsJpegWithName)

- (void) saveAsJpegWithName:(NSString*) fileName
{
    // Cache the reduced image
    NSData *imageData = [self TIFFRepresentation];
    NSBitmapImageRep *imageRep = [NSBitmapImageRep imageRepWithData:imageData];
    NSDictionary *imageProps = [NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:1.0] forKey:NSImageCompressionFactor];
    imageData = [imageRep representationUsingType:NSJPEGFileType properties:imageProps];
    [imageData writeToFile:fileName atomically:NO];        
}

@end

L'appel à « TIFFRepresentation » est essentiel, sinon vous ne pouvez pas obtenir une image valide.

Je ne sais pas sur le reste d'entre vous, mais je préfère manger mon plein enchilada. Ce qui est décrit ci-dessus travail et rien ne va pas avec, mais je l'ai trouvé quelques petites choses à l'écart. Ici, je vais mettre en évidence mes observations:

  • Tout d'abord le meilleur est fourni une représentation qui semble être 72 DPI même si la résolution de l'image est supérieure à celle. Donc, vous perdez résolution
  • Deuxième images au sujet de ce que plusieurs pages telles que celles en GIF animé ou PDF. Allez-y, essayez un GIF animé, vous trouverez l'animation perdue
  • Enfin les métadonnées telles que EXIF, GPS, etc ... les données seront perdues.

Donc, si vous voulez convertir cette image, voulez-vous vraiment perdre sur tout cela? Si vous souhaitez manger votre repas complet, puis laisse lire ...

Parfois, et je ne parle parfois il n'y a rien de mieux que de bien ole vieux développement scolaire. Ouais, ce signifie que nous devons faire un peu de travail!

Soit s commencer:

Je crée une catégorie dans NSData. Ce sont des méthodes de classe parce que vous voulez que ces choses soient thread-safe et il n'y a rien plus sûr que de mettre vos trucs sur la pile. Il existe deux types de méthodes, l'une pour la sortie d'images non-multi-pages et une pour la sortie des images de plusieurs pages.

Liste des images simples: JPG, PNG, BMP, JPEG-2000

Liste des multiples images: PDF, GIF, TIFF

Tout d'abord créer un espace de données mutable dans la mémoire.

NSMutableData * imageData    = [NSMutableData data];

Deuxième obtenir un CGImageSourceRef. Ouais sonnant laid est déjà pas. Il est pas si mal, Continuons ... Vous voulez vraiment l'image source et non une représentation ou morceau NSImage des données. Cependant, nous avons un petit problème. La source peut ne pas être compatible, assurez-vous de vérifier votre UTI contre ceux énumérés de CGImageSourceCopyTypeIdentifiers ()

Une partie du code:

CGImageSourceRef imageSource = nil;
if ( /* CHECK YOUR UTI HERE */ )
    return CGImageSourceCreateWithURL( (CFURLRef)aURL, nil );

NSImage * anImage = [[NSImage alloc] initWithContentsOfURL:aURL];

if ( anImage )
    return CGImageSourceCreateWithData( (CFDataRef)[anImage TIFFRepresentation], nil );

Attendez une seconde, pourquoi est-il NSImage? Eh bien il y a des formats qui ne sont pas de métadonnées et CGImageSource ne supporte pas, mais ce sont des images valides. Un exemple est vieux images PICT style.

Maintenant, nous avons un CGImageSourceRef, assurez-vous que ce n'est pas nul et nous allons obtenir un CGImageDestinationRef maintenant. Wow tous ces ref est de garder la trace. Nous sommes à ce jour à 2!

Nous allons utiliser cette fonction: CGImageDestinationCreateWithData ()

  • 1er PARAM est votre imageData (cast CFMutableDataRef)
  • 2 PARAM est votre UTI sortie, rappelez-vous la liste ci-dessus. (par exemple. kUTTypePNG)
  • 3 PARAM est le nombre d'images à enregistrer. Pour les fichiers d'image unique cette est 1 sinon vous pouvez simplement utiliser les éléments suivants:

    CGImageSourceGetCount (ImageSource);

  • 4 PARAM est nulle.

Vérifiez si vous avez ce CGImageDestinationRef et maintenant nous allons ajouter nos images de la source en elle ... ce comprendra également tout / toutes les métadonnées et de conserver la résolution.

Pour plusieurs images on boucle:

for ( NSUInteger i = 0; i < count; ++i )
                CGImageDestinationAddImageFromSource( imageDest, imageSource, i, nil );

Pour une seule image, il est une ligne de code à l'index 0:

CGImageDestinationAddImageFromSource( imageDest, imageSource, 0, nil);

Ok, finaliser lequel il est écrit sur le disque ou le conteneur de données:

CGImageDestinationFinalize( imageDest );

Pour que Mutable les données du début a toutes nos données d'image et de métadonnées dans maintenant.

Sommes-nous encore fait? Presque, même avec la collecte des ordures vous devez ménage! Rappelez-vous deux sa Ref pour la source et un pour la destination alors faites un CFRelease ()

Maintenant, nous fait et ce que vous vous retrouvez avec une image convertie en conservant toutes ses métadonnées, la résolution, etc ...

Méthodes de catégorie Mon NSData ressemblent à ceci:

+ (NSData *) JPGDataFromURL:(NSURL *)aURL;
+ (NSData *) PNGDataFromURL:(NSURL *)aURL;
+ (NSData *) BMPDataFromURL:(NSURL *)aURL;
+ (NSData *) JPG2DataFromURL:(NSURL *)aURL;

+ (NSData *) PDFDataFromURL:(NSURL *)aURL;
+ (NSData *) GIFDataFromURL:(NSURL *)aURL;
+ (NSData *) TIFFDataFromURL:(NSURL *)aURL;

Qu'en est-il redimensionnement ou ICO / ICNS? Ceci est un autre jour, mais en résumé, vous devez d'abord aborder le redimensionnement ...

  1. Créer un contexte avec une nouvelle taille: CGBitmapContextCreate ()
  2. Obtenir l'une image réf de l'index: CGImageSourceCreateImageAtIndex ()
  3. Obtenir une copie des métadonnées: CGImageSourceCopyPropertiesAtIndex ()
  4. Dessine l'image dans le contexte: CGContextDrawImage ()
  5. Obtenir l'image redimensionnée du contexte: CGBitmapContextCreateImage ()
  6. Maintenant, ajoutez l'image et les métadonnées du Dest Ref: CGImageDestinationAddImage ()

rincer et répéter à plusieurs-images intégrées dans la source.

La seule différence entre un ICO et ICNS est que l'on est une seule image tandis que l'autre est multiple-images dans un seul fichier. Je parie que vous pouvez deviner qui est qui ?! ;-) Pour ces formats, vous devrez redimensionner à une taille particulière autre erreur découlera. Le processus est bien exactement la même où vous utilisez l'UTI correcte, mais le redimensionnement est un peu plus stricte.

Ok espoir cela aide les autres là-bas et vous êtes aussi pleins que je suis maintenant!

Opps, oublié de mentionner. Lorsque vous obtenez l'objet NSData faire ce que vous voulez avec elle, comme writeToFile, writeToURL ou créer un autre diable NSImage si vous voulez.

Bonne programmation!

Enregistrer sous PNG en utilisant swift3

import AppKit

extension NSImage {
    @discardableResult
    func saveAsPNG(url: URL) -> Bool {
        guard let tiffData = self.tiffRepresentation else {
            print("failed to get tiffRepresentation. url: \(url)")
            return false
        }
        let imageRep = NSBitmapImageRep(data: tiffData)
        guard let imageData = imageRep?.representation(using: .PNG, properties: [:]) else {
            print("failed to get PNG representation. url: \(url)")
            return false
        }
        do {
            try imageData.write(to: url)
            return true
        } catch {
            print("failed to write to disk. url: \(url)")
            return false
        }
    }
}

Swift 4.2 Solution

public extension NSImage {
    public func writePNG(toURL url: URL) {

        guard let data = tiffRepresentation,
              let rep = NSBitmapImageRep(data: data),
              let imgData = rep.representation(using: .png, properties: [.compressionFactor : NSNumber(floatLiteral: 1.0)]) else {

            Swift.print("\(self) Error Function '\(#function)' Line: \(#line) No tiff rep found for image writing to \(url)")
            return
        }

        do {
            try imgData.write(to: url)
        }catch let error {
            Swift.print("\(self) Error Function '\(#function)' Line: \(#line) \(error.localizedDescription)")
        }
    }
}

Swift Style:

if let imgRep = image?.representations[0] as? NSBitmapImageRep
{
      if let data = imgRep.representationUsingType(NSBitmapImageFileType.NSPNGFileType, properties: [:])
      {
           data.writeToFile("/path/to/file.png", atomically: false)
      }
}

Juste une garantie à l'approche de travail en utilisant SWIFT:

J'ai un « Image bien » où l'utilisateur peut déposer une image. Et ce "Image Well" a une propriété d'image (de type NSImage) accessible par la sortie:

@IBOutlet weak var imageWell: NSImageView!

Et le code qui sauve cette image (vous pouvez le mettre dans l'action du bouton) est la suivante:

if imageWell.image != nil {
   let bMImg = NSBitmapImageRep(data: (imageWell?.image?.TIFFRepresentation)!)
   let dataToSave = bMImg?.representationUsingType(NSBitmapImageFileType.NSJPEGFileType, properties: [NSImageCompressionFactor : 1])
   dataToSave?.writeToFile("/users/user/desktop/image.jpg", atomically: true)
}

Dans la 1ère ligne du code donné nous vérifions si notre image bien a une image.

Dans la 2ème ligne, nous faisons une représentation bitmap de cette image.

Dans la 3ème ligne, nous transformons notre BitmapRepresentation à un type JPG avec un facteur de compression réglé sur "1" (pas de compression).

Dans la 4ème ligne nous enregistrer les données de JPG avec un chemin donné. . « atomiquement: true » signifie que le fichier est enregistré en une seule pièce et qui nous assure que l'opération sera Successfull

N.B.:. Vous pouvez utiliser un autre NSBitmapImageFileType dans la 3ème ligne, pour enregistrer votre image dans un autre format. Il a beaucoup:

NSBitmapImageFileType.NSBMPFileType
NSBitmapImageFileType.NSGIFFileType
NSBitmapImageFileType.NSPNGFileType

etc.

Pour l'aide avec le code multi-plateforme, je mis en œuvre une ofUIImagePNGRepresentation() version qui fonctionne sur Mac (et les utilisations NSImage).

#if os(macOS)

public func UIImagePNGRepresentation(_ image: NSImage) -> Data? {
    guard let cgImage = image.cgImage(forProposedRect: nil, context: nil, hints: nil)
        else { return nil }
    let imageRep = NSBitmapImageRep(cgImage: cgImage)
    imageRep.size = image.size // display size in points
    return imageRep.representation(using: .png, properties: [:])
}

#endif

Utilisation:

if let data = UIImagePNGRepresentation(myImage) {
    do { try data.write(to: url, options: [.atomic]) }
    catch let error { print("Error writing image (\(error))") }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top