72 votos

Cómo guardar un NSImage como un archivo nuevo

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

Gracias por responder a mi "noobish" pregunta.

161voto

Pegolon Puntos 1904

Usted puede agregar una categoría NSImage como este

@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, usted no puede obtener una imagen válida.

50voto

garph0 Puntos 1134

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

33voto

Arvin Puntos 1392

No estoy seguro sobre el resto de ustedes, pero prefiero comer mi enchilada completa. De lo descrito anteriormente funciona y no hay nada malo con ella, pero he encontrado un par de cosas que quedan fuera. Aquí quiero destacar mis observaciones:

  • Primero el mejor representación es siempre lo que parece ser de 72 DPI incluso si la resolución de la imagen es mayor que eso. Estás perdiendo resolución
  • Segundo ¿qué acerca de multi-página de las imágenes, tales como aquellos en los GIFs animados o Los archivos pdf. Vaya por delante, se trate de un GIF animado, usted encontrará la animación perdido
  • Por último, los metadatos como EXIF, GPS, etc...los datos se perderán.

Así que si quieres convertir esa imagen, ¿de verdad quieres perder todo esto? Si quiere comer su comida completa, entonces vamos a leer en...

A veces, y digo a veces no hay nada mejor que una buena ole de la vieja escuela de desarrollo. Sí, eso significa que tenemos que hacer un poco de trabajo!

Vamos a empezar:

Puedo crear una categoría en NSData. Estos son los métodos de la clase porque desea estas cosas a los subprocesos 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 la no-multi-página de imágenes y uno para la salida de los multi-página de imágenes.

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

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

Primero crear un mutable espacio de datos en la memoria.

NSMutableData * imageData    = [NSMutableData data];

Segundo, obtener una CGImageSourceRef. Sí, suena feo ya no lo es. No es tan malo, vamos a seguir adelante... Usted realmente desea que 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, así que asegúrese de verificar que su UTI contra los mencionados de CGImageSourceCopyTypeIdentifiers()

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 segundo, ¿por qué es NSImage no? Bueno, hay algunos formatos que no tienen metadatos y CGImageSource no apoyo, pero estas son las imágenes válidas. Un ejemplo es el antiguo estilo de las imágenes PICT.

Ahora tenemos una CGImageSourceRef, asegúrese de que no es nulo y, a continuación, vamos a conseguir ahora una CGImageDestinationRef. Wow todos estos ref seguir el rastro. Hasta ahora estamos en la 2!

Vamos a utilizar esta función: CGImageDestinationCreateWithData()

  • 1er Parámetro es su imageData (cast CFMutableDataRef)
  • 2º Param es su salida de IU, recuerde que la lista de arriba. (por ejemplo, kUTTypePNG)
  • 3er Parámetro es el número de imágenes que desea guardar. Para archivos de una imagen a esta es 1 de otra manera puede utilizar simplemente el siguiente:

    CGImageSourceGetCount( imageSource );

  • 4º Parámetro es nulo.

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

Para múltiples imágenes que nos bucle:

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

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

CGImageDestinationAddImageFromSource( imageDest, imageSource, 0, nil);

Ok, que finalizará el que escribe en el disco o el contenedor de datos:

CGImageDestinationFinalize( imageDest );

De modo que los Datos Mutables desde el principio tiene todos nuestros datos de la imagen y de los metadatos en el ahora.

Se nos ha hecho todavía? Casi, incluso con la recolección de basura tiene que limpiar! Recuerde dos Ref uno para la fuente y otro para el destino con el fin de hacer un CFRelease()

Ahora estamos haciendo y lo que termina con una imagen convertida manteniendo todas sus metadatos, resolución, etc...

Mi NSData categoría de los métodos de 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;

Lo que sobre el cambio de tamaño o ICO / ICNS? Esto es para otro día, pero en resumen, primero aparejos de cambio de tamaño...

  1. Crear un contexto con el nuevo tamaño: CGBitmapContextCreate()
  2. Obtener la imagen ref de índice: CGImageSourceCreateImageAtIndex()
  3. Obtener 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 para la Dest Ref: CGImageDestinationAddImage()

Enjuague y repita para múltiples imágenes incrustadas en la fuente.

La única diferencia entre un ICO y ICNS es que uno es de una sola imagen, mientras que el otro es de varias imágenes en un archivo. Apuesto a que puedo adivinar cual es cual?! ;-) Para estos formatos tiene para cambiar el tamaño hasta un tamaño determinado, de lo contrario, el ERROR se producirá. El proceso a pesar de que es exactamente el mismo que utiliza el adecuado UTI, pero el cambio de tamaño es un poco más estricto.

Ok espero que esto ayude a otros y son tan completo como estoy ahora!

Opps, se olvidó de mencionar. Cuando usted consigue el NSData objeto de hacer lo que quiera con ella, tales como writeToFile, writeToURL, o diablos crear otro NSImage si quieres.

Feliz codificación!

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X