Pregunta

¿Cómo puedo guardar un NSImage como un nuevo archivo (png, jpg, ...) en un determinado directorio?

¿Fue útil?

Solución

hacer algo como esto:

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

Otros consejos

Se podría añadir una categoría a NSImage como esto

@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 llamada a "TIFFRepresentation" es esencial de lo contrario no puede obtener una imagen válida.

No estoy seguro sobre el resto de ustedes, pero yo prefiero comer mi enchilada completa. Lo que se ha descrito anteriormente voluntad de trabajo y no hay nada malo en ello, pero he encontrado algunas cosas que quedan fuera. Aquí voy a destacar mis observaciones:

  • En primer lugar la mejor representación se ofrece lo que parece ser 72 DPI incluso si la resolución de la imagen es mayor que eso. Así que usted está perdiendo Resolución
  • En segundo lugar ¿qué pasa con las imágenes de varias páginas como las de GIF animados o PDFs. Vaya por delante, tratar un GIF animado, se encuentra la animación perdido
  • Por último los metadatos como EXIF, GPS, etc ... los datos se perderán.

Así que si desea convertir esa imagen, lo que realmente quiere perder a cabo en todo esto? Si desea comer su comida completa, luego le permite leer en ...

A veces, y quiero decir a veces no hay nada mejor que un buen desarrollo de la vieja escuela ole. Si eso significa que tenemos que hacer un poco de trabajo!

get Vamos a empezar:

crear una categoría en NSData. Estos son los métodos de clase porque quiere estas cosas para ser seguro para hilos y no hay nada más seguro que poner sus cosas en la pila. Hay dos tipos de métodos, uno para la salida de las imágenes no de varias páginas y otro para la salida de las imágenes de varias páginas.

Lista de imágenes individuales: JPG, PNG, BMP, JPEG-2000

Lista de varias imágenes: PDF, GIF, TIFF

En primer lugar crear un espacio de datos mutables en la memoria.

NSMutableData * imageData    = [NSMutableData data];

En segundo lugar conseguir un CGImageSourceRef. Sí que suena feo ya no lo es. No es tan malo, vamos a seguir adelante ... ¿De verdad quieres la imagen de origen no es una representación o NSImage fragmento de datos. Sin embargo, tenemos un pequeño problema. La fuente puede no ser compatible, por lo que asegúrese de comprobar su infección del tracto urinario en contra de los que se enumeran CGImageSourceCopyTypeIdentifiers ()

Algunos código:

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

Espera un momento, ¿por qué es NSImage allí? Bueno, hay algunos formatos que no tienen metadatos y CGImageSource no soporta, pero estos son imágenes válidas. Un ejemplo es las imágenes PICT estilo antiguo.

Ahora tenemos una CGImageSourceRef, asegúrese de que no es nula y luego dejar de Get a CGImageDestinationRef. Wow todos estos ref es no perder de vista. Hasta el momento estamos a 2!

Vamos a utilizar esta función: CGImageDestinationCreateWithData ()

  • Param primero es su propiedad imageData (molde CFMutableDataRef)
  • Param segundo es su salida de IU, recordar la lista anterior. (p.ej. kUTTypePNG)
  • Param tercero es el recuento de imágenes de ahorrar. Para una sola imagen archivos.Esta 1 en caso contrario se puede simplemente usar lo siguiente:

    CGImageSourceGetCount (ImageSource);

  • cuarto Param es nula.

Compruebe para ver si tiene este CGImageDestinationRef y ahora vamos a añadir nuestras imágenes de la fuente en ella ... esto también va a incluir cualquier / todos los metadatos y retener la resolución.

Para múltiples imágenes que bucle:

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

Para obtener una sola imagen que es una línea de código en el índice 0:

CGImageDestinationAddImageFromSource( imageDest, imageSource, 0, nil);

Ok, lo completara el que lo escribe en disco o contenedor de datos:

CGImageDestinationFinalize( imageDest );

Para que mutable de datos desde el principio tiene todos nuestros datos de imágenes y metadatos en ello ahora.

¿Estamos todavía hace? Casi, incluso con la recolección de basura que tiene que limpiar-up! Recuerde dos uno de Referencia para la fuente y otro para el destino, para hacer un CFRelease ()

Ahora estamos haciendo y lo que usted termina con una conserva todos sus metadatos, resolución, etc ...

imagen convertida

Mi métodos categoría NSData este aspecto:

+ (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é hay de cambiar el tamaño o la OIC / ICNS? Esto es para otro día, pero en resumen que abordar en primer lugar el cambio de tamaño ...

  1. Crear un contexto con el nuevo tamaño: CGBitmapContextCreate ()
  2. Obtener el árbitro con una imagen de índice: CGImageSourceCreateImageAtIndex ()
  3. Obtenga una copia de los metadatos: CGImageSourceCopyPropertiesAtIndex ()
  4. Dibujar la imagen en el contexto: CGContextDrawImage ()
  5. Obtener la imagen redimensionada por el contexto: CGBitmapContextCreateImage ()
  6. Ahora agregue la imagen y metadatos al Dest Ref: CGImageDestinationAddImage ()

Enjuague y repita los fines de múltiples imágenes incrustadas en la fuente.

La única diferencia entre un ICO y ICNS es que se trata de una sola imagen, mientras que el otro es-varias imágenes en un archivo. Apuesta se puede adivinar que es lo que ?! ;-) Para estos formatos hay que cambiar el tamaño a un tamaño particular, de lo contrario se producirá ERROR. Aunque el proceso es exactamente el mismo en el que utiliza la UTI adecuada, pero el cambio de tamaño es un poco más estricta.

esperanza Ok esto ayuda a otros por ahí y que son tan completa como lo estoy ahora!

Opps, se olvidó de mencionar. Cuando se obtiene el objeto NSData hacer lo que quiera con él como WriteToFile, writeToURL, o diablos crear otro NSImage si lo desea.

feliz de codificación!

guardar como PNG utilizando 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 Solución

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 Estilo:

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

Sólo una más garantizado para enfoque de trabajo utilizando SWIFT:

Tengo una "imagen bien" dónde el usuario puede soltar cualquier imagen. Y esta "imagen bien" tiene una propiedad de imagen (de tipo NSImage) se accede a través de salida:

@IBOutlet weak var imageWell: NSImageView!

Y el código que guarda esta imagen (se puede poner dentro de la acción del botón) es:

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

En la primera línea del código dado que comprobar si nuestra imagen bien tiene una imagen.

En la segunda línea que hacen una representación de mapa de bits de esa imagen.

En la tercera línea convertimos nuestra BitmapRepresentation a un tipo JPG con un conjunto factor de compresión a "1" (sin compresión).

En la cuarta línea que guardar los datos en formato JPG con una trayectoria determinada. . "atómicamente: verdaderos" significa que el archivo se guarda como una sola pieza y que nos asegura que la operación será exitosa

N.B:. Puede utilizar otro NSBitmapImageFileType en la tercera línea, para guardar la imagen a otro formato. Tiene un montón:

NSBitmapImageFileType.NSBMPFileType
NSBitmapImageFileType.NSGIFFileType
NSBitmapImageFileType.NSPNGFileType

etc.

Para ayuda con el código de plataforma cruzada, que implementa una versión ofUIImagePNGRepresentation() que se ejecuta en Mac (y usos 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

Uso:

if let data = UIImagePNGRepresentation(myImage) {
    do { try data.write(to: url, options: [.atomic]) }
    catch let error { print("Error writing image (\(error))") }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top