Domanda

Come posso salvare un NSImage come un nuovo file (PNG, JPG, ...) in una determinata directory?

È stato utile?

Soluzione

fare qualcosa di simile:

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

Altri suggerimenti

Si potrebbe aggiungere una categoria per NSImage come questo

@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

La chiamata al "TIFFRepresentation" è essenziale altrimenti non si può ottenere un'immagine valida.

Non sono sicuro circa il resto di voi, ma io preferisco mangiare la mia piena enchilada. Quanto sopra descritto il lavoro di volontà e non c'è niente di sbagliato con esso, ma ho trovato un paio di cose lasciate fuori. Qui mi limiterò a mettere in evidenza le mie osservazioni:

  • In primo luogo la migliore rappresentazione è previsto che sembra essere 72 DPI anche se la risoluzione dell'immagine è maggiore di quella. Così si stanno perdendo risoluzione
  • In secondo luogo per quanto riguarda le immagini multi-pagina, come quelli in GIF animate o PDF. Vai avanti, provare una GIF animata, si trova l'animazione perso
  • Infine tutti i metadati come EXIF, GPS, ecc ... i dati saranno persi.

Quindi, se si desidera convertire l'immagine, non si vuole veramente a perdere su tutto questo? Se si desidera mangiare il vostro pasto completo, poi lascia a leggere ...

A volte e intendo a volte non c'è niente di meglio di un buon sviluppo della vecchia scuola ole. Sì che significa che dobbiamo fare un po 'di lavoro!

get Let iniziato:

I creare una categoria in NSData. Questi sono metodi della classe perché si vuole queste cose siano thread-safe e non c'è nulla di più sicuro di mettere la vostra roba in pila. Ci sono due tipi di metodi, uno per l'uscita di immagini non più pagine e uno per l'uscita delle immagini più pagine.

Elenco di singole immagini: JPG, PNG, BMP, JPEG-2000

Lista di immagini multiple: PDF, GIF, TIFF

Per prima cosa creare uno spazio di dati mutabile nella memoria.

NSMutableData * imageData    = [NSMutableData data];

Secondo ottenere un CGImageSourceRef. Si suona brutto già non è vero. Non è poi così male, cerchiamo di andare avanti ... Si vuole veramente l'immagine di origine non è una rappresentazione o NSImage blocco di dati. Tuttavia, noi abbiamo un piccolo problema. La fonte potrebbe non essere compatibile, quindi assicuratevi di controllare il vostro UTI contro quelli elencati da CGImageSourceCopyTypeIdentifiers ()

Alcuni codice:

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 );

Aspetta un secondo, perché è NSImage lì? Beh ci sono alcuni formati che non hanno metadati e CGImageSource non supporta, ma queste sono immagini valide. Un esempio è immagini PICT vecchio stile.

Ora abbiamo un CGImageSourceRef, assicurarsi che non è pari a zero e poi andiamo ora ottenere un CGImageDestinationRef. Wow tutti questi Ref per tenere traccia dei. Finora siamo a 2!

Si utilizzerà questa funzione: CGImageDestinationCreateWithData ()

  • 1 ° Param è il tuo imageData (Cast CFMutableDataRef)
  • 2 ° Param è l'output UTI, ricordare l'elenco di cui sopra. (per esempio. kUTTypePNG)
  • 3 ° Param è il conteggio delle immagini da salvare. Per singolo file di immagine presente è 1 altrimenti si può semplicemente utilizzare il seguente:

    CGImageSourceGetCount (ImageSource);

  • 4 Param è pari a zero.

Controlla per vedere se si dispone di questo CGImageDestinationRef e ora aggiungiamo le nostre immagini dalla sorgente in esso ... questo includerà anche tutti i metadati qualsiasi / e mantenere la risoluzione.

Per più immagini ci ciclo:

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

Per singola immagine è una riga di codice in corrispondenza dell'indice 0:

CGImageDestinationAddImageFromSource( imageDest, imageSource, 0, nil);

Ok, finalizzare esso che scrive su disco o dati contenitore:

CGImageDestinationFinalize( imageDest );

In modo che Mutevole dati fin dall'inizio ha tutti i nostri dati di immagini e metadati in ora.

Stiamo ancora finito? Quasi, anche con la raccolta dei rifiuti si deve pulire-up! Ricordate due uno di Ref per l'origine e uno per la destinazione in modo da fare un CFRelease ()

Ora ci sono fatti e che cosa si finisce con è un immagine convertita conservando tutta la sua metadati, risoluzione, ecc ...

Metodi di categoria Il mio NSData simile a questa:

+ (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;

Che dire di ridimensionamento o ICO / ICNS? Questo è per un altro giorno, ma in sintesi la prima volta ad affrontare il ridimensionamento ...

  1. Creare un contesto con il nuovo formato: CGBitmapContextCreate ()
  2. Ottenere l'arbitro un'immagine dall'indice: CGImageSourceCreateImageAtIndex ()
  3. Ottenere una copia dei metadati: CGImageSourceCopyPropertiesAtIndex ()
  4. Disegna l'immagine nel contesto: CGContextDrawImage ()
  5. Prendi l'immagine ridimensionata dal contesto: CGBitmapContextCreateImage ()
  6. Ora aggiungere l'immagine e metadati al Dest Rif: CGImageDestinationAddImage ()

Sciacquare e ripetere per più-immagini incorporate nella sorgente.

L'unica differenza tra un ICO e ICNS è che uno è una sola immagine, mentre l'altro è più-immagini in un unico file. Scommetto che si può intuire che è che ?! ;-) Per questi formati si deve ridimensionare fino a una dimensione particolare in caso contrario ERRORE ne conseguiranno. Il processo però è esattamente la stessa in cui si utilizza il corretto UTI, ma il ridimensionamento è un po 'più rigoroso.

Ok speranza che questo aiuta altri là fuori e si è pieni come sono adesso!

Opps, dimenticato di dire. Quando si ottiene l'oggetto NSData fare come si vuole con esso, come writeToFile, writeToURL, o diamine creare un altro NSImage se si desidera.

Happy codifica!

Salva come PNG utilizzando 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 Soluzione

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)
      }
}

Ancora una garanzia di approccio al lavoro con SWIFT:

Ho un "Immagine," dove l'utente può rilasciare qualsiasi immagine. E questo "Immagine Well" ha una proprietà di immagine (di tipo NSImage) si accede tramite presa di corrente:

@IBOutlet weak var imageWell: NSImageView!

E il codice che salva questa immagine (lo si può mettere dentro l'azione tasto) è:

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)
}

Nel 1 ° riga del codice dato che controllare se la nostra immagine Bene ha un'immagine.

Nel 2 ° linea facciamo una rappresentazione bitmap di tale immagine.

Nel 3 ° linea di convertiamo il nostro BitmapRepresentation ad un tipo JPG con un set fattore di compressione a "1" (nessuna compressione).

In linea 4 salviamo i dati JPG con un determinato percorso. . "atomicamente: vere e proprie" significa che il file viene salvato come un unico pezzo e che ci assicura che l'operazione sarà successo

NB:. È possibile utilizzare un altro NSBitmapImageFileType nel 3 ° linea, per salvare l'immagine in un altro formato. Ha un sacco:

NSBitmapImageFileType.NSBMPFileType
NSBitmapImageFileType.NSGIFFileType
NSBitmapImageFileType.NSPNGFileType

ecc.

Per aiutare con il codice cross-platform, ho implementato una versione ofUIImagePNGRepresentation() che gira su Mac (e gli usi 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

Utilizzo:

if let data = UIImagePNGRepresentation(myImage) {
    do { try data.write(to: url, options: [.atomic]) }
    catch let error { print("Error writing image (\(error))") }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top