Как сохранить NSImage в качестве нового файла (png, jpg,...) в определенном каталоге?
Как сохранить NSImage в качестве нового файла
Ответ 1
Сделайте что-то вроде этого:
NSBitmapImageRep *imgRep = [[image representations] objectAtIndex: 0];
NSData *data = [imgRep representationUsingType: NSPNGFileType properties: nil];
[data writeToFile: @"/path/to/file.png" atomically: NO];
Ответ 2
Вы можете добавить категорию в NSImage, как это
@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
Вызов "TIFFRepresentation" имеет важное значение, иначе вы не сможете получить действительное изображение.
Ответ 3
Не уверен, что ты остаешься, но я предпочитаю есть свою полную энчиладу. То, что описано выше, будет работать, и с ним ничего не случилось, но я обнаружил, что некоторые вещи остались без внимания. Здесь я остановлюсь на своих наблюдениях:
- Сначала предоставляется наилучшее представление, которое, по-видимому, составляет 72 DPI даже если разрешение изображения больше. Итак, вы теряете разрешение
- Во-вторых, о многостраничных изображениях, например, в анимированных GIF файлах или PDF файлы. Идите дальше, попробуйте анимированный GIF, вы потеряете анимацию
- В конечном итоге любые метаданные, такие как EXIF, GPS и т.д., будут потеряны.
Итак, если вы хотите преобразовать это изображение, вы действительно хотите проиграть все это? Если вы хотите съесть свою полноценную еду, тогда читайте дальше...
Иногда, и я имею в виду, иногда нет ничего лучше, чем хорошая разработка старой школы. Да, это означает, что нам нужно немного поработать!
Давайте начнем:
Я создаю категорию в NSData. Это методы класса, потому что вы хотите, чтобы эти вещи были потокобезопасными, и нет ничего более безопасного, чем помещение ваших вещей в стек. Существует два типа методов: один для вывода не-многостраничных изображений и один для вывода многостраничных изображений.
Список отдельных изображений: JPG, PNG, BMP, JPEG-2000
Список нескольких изображений: PDF, GIF, TIFF
Сначала создайте изменяемое пространство данных в памяти.
NSMutableData * imageData = [NSMutableData data];
Во-вторых, получите CGImageSourceRef. Да, звучание уродливое уже не так. Это не так уж плохо, продолжайте идти... Вы действительно хотите, чтобы исходное изображение не было представлением или блоком данных NSImage. Однако у нас есть небольшая проблема. Источник может быть несовместимым, поэтому убедитесь, что вы проверили свой UTI на те, которые перечислены в CGImageSourceCopyTypeIdentifiers()
Некоторые коды:
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 );
Подождите секунду, почему там NSImage? Ну, есть некоторые форматы, у которых нет метаданных, а CGImageSource не поддерживается, но это допустимые изображения. Примером являются изображения PICT старого стиля.
Теперь у нас есть CGImageSourceRef, убедитесь, что он не нуль, а затем давайте теперь получить CGImageDestinationRef. Wow все эти ref отслеживать. Пока мы находимся в 2!
Мы будем использовать эту функцию: CGImageDestinationCreateWithData()
- 1-й параметр - ваш образ (cast CFMutableDataRef)
- Второй параметр - ваш выход UTI, запомните список выше. (например. kUTTypePNG)
-
3rd Param - это количество изображений для сохранения. Для отдельных файлов изображений это 1, вы можете просто использовать следующее:
CGImageSourceGetCount (imageSource);
-
4-й параметр равен нулю.
Проверьте, есть ли у вас этот CGImageDestinationRef и теперь добавьте в него наши изображения из источника... это также будет включать в себя все/все метаданные и сохранить разрешение.
Для нескольких изображений цикл:
for ( NSUInteger i = 0; i < count; ++i )
CGImageDestinationAddImageFromSource( imageDest, imageSource, i, nil );
Для одного изображения это одна строка кода с индексом 0:
CGImageDestinationAddImageFromSource( imageDest, imageSource, 0, nil);
Ок, завершите его, который записывает его на диск или контейнер данных:
CGImageDestinationFinalize( imageDest );
Итак, что Mutable Data с самого начала содержит все наши данные изображения и метаданные в нем.
Готовы ли мы еще? Почти даже с сборкой мусора вы должны очистить! Помните два Ref один для источника и один для назначения, поэтому CFRelease()
Теперь мы закончили, и в итоге получим преобразованное изображение, сохраняющее все его метаданные, разрешение и т.д.
Мои методы категорий NSData выглядят следующим образом:
+ (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;
Как насчет изменения размера или ICO/ICNS? Это на другой день, но в итоге вы сначала решаете изменение размера...
- Создайте контекст с новым размером: CGBitmapContextCreate()
- Получить ссылку ref из индекса: CGImageSourceCreateImageAtIndex()
- Получить копию метаданных: CGImageSourceCopyPropertiesAtIndex()
- Нарисуйте изображение в контексте: CGContextDrawImage()
- Получить измененное изображение из контекста: CGBitmapContextCreateImage()
- Теперь добавьте изображение и метаданные в Dest Ref: CGImageDestinationAddImage()
Промыть и повторить для нескольких изображений, встроенных в источник.
Единственное различие между ICO и ICNS заключается в том, что один является одним изображением, а другой - несколькими изображениями в одном файле. Ставка, вы можете догадаться, что это?!;-) Для этих форматов вам необходимо изменить размер до определенного размера, иначе появится ERROR. Процесс, хотя и является тем же самым, когда вы используете правильный UTI, но изменение размера немного более строгое.
Хорошо, надеюсь, что это поможет другим, и вы настолько полны, насколько я есть сейчас!
Оппс, забыл упомянуть. Когда вы получаете объект NSData, как вам нужно, например writeToFile, writeToURL или heck, создайте еще одно NSImage, если хотите.
Счастливое кодирование!
Ответ 4
сохранить как PNG с помощью 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
}
}
}
Ответ 5
Стиль Swift:
if let imgRep = image?.representations[0] as? NSBitmapImageRep
{
if let data = imgRep.representationUsingType(NSBitmapImageFileType.NSPNGFileType, properties: [:])
{
data.writeToFile("/path/to/file.png", atomically: false)
}
}
Ответ 6
Решение Swift 4
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.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.self) Error Function '\(#function)' Line: \(#line) \(error.localizedDescription)")
}
}
}
Ответ 7
Еще один гарантированный подход к работе с использованием SWIFT:
У меня есть "Image Well", где пользователь может удалить любое изображение. И эта "Image Well" имеет свойство изображения (типа NSImage), доступ к которому осуществляется через выход:
@IBOutlet weak var imageWell: NSImageView!
И код, который сохраняет это изображение (вы можете поместить его внутри действия кнопки):
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)
}
В первой строке данного кода мы проверяем, есть ли у нашего изображения Ну изображение.
Во второй строке мы делаем растровое изображение этого изображения.
В третьей строке мы преобразуем наше представление BitmapRepresentation в тип JPG с коэффициентом сжатия, установленным в "1" (без сжатия).
В 4-й строке мы сохраняем данные JPG с заданным путем. "atomically: true" означает, что файл сохраняется как одна часть, и это гарантирует, что операция будет успешной.
N.B.: Вы можете использовать другой NSBitmapImageFileType в третьей строке, чтобы сохранить изображение в другом формате. В нем много:
NSBitmapImageFileType.NSBMPFileType
NSBitmapImageFileType.NSGIFFileType
NSBitmapImageFileType.NSPNGFileType
и др.