Вопрос

Как я могу сохранить NSImage как новый файл (PNG, JPG, ...) в определенном каталоге?

Это было полезно?

Решение

Сделать что-то вроде этого:

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

Другие советы

Вы можете добавить категорию в 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» имеет важное значение, иначе вы не можете получить действительное изображение.

Не уверен в остальных тебе, но я предпочитаю есть свою полную энчиладу. То, что описано выше, будет работать, и с ним ничего не так, но я нашел несколько вещей. Здесь я выделим мои наблюдения:

  • Первое лучшее представление предусмотрено, что, кажется, 72 dpi, даже если разрешение изображения больше, чем это. Так что вы теряете резолюцию
  • Во-вторых, как насчет многостраничных изображений, таких как в анимированных GIFS или PDFS. Продолжайте, попробуйте анимированный гиф, вы найдете терянную анимацию
  • Наконец, любые метаданные, такие как EXIF, GPS и т. Д., будут потеряны.

Так что, если вы хотите преобразовать это изображение, вы действительно хотите потерять все это? Если вы хотите съесть свою полную еду, то давайте прочитаем ...

Иногда, и я имею в виду иногда нет ничего лучше, чем хорошее развитие старой школы OLE. Да, это значит, что мы должны сделать немного работы!

Давайте начнем:

Я создаю категорию в nsdata. Это методы классов, потому что вы хотите, чтобы эти вещи были безопасными потоками, и нет ничего безопасного, чем ставить вещи на стек. Существует два типа методов, один для выхода невлимного страничных изображений и один для вывода многостраничных изображений.

Список однократные изображения: JPG, PNG, BMP, JPEG-2000

Список нескольких изображений: PDF, GIF, TIFF

Сначала создайте смежное пространство данных в памяти.

NSMutableData * imageData    = [NSMutableData data];

Второе получите cgimageourceref. Да, звучащее уродливое уже не так. Это не так уж плохо, давайте продолжим ... вы действительно хотите, чтобы исходное изображение не представление или NSImage Data. Тем не менее, у нас есть небольшая проблема. Источник может не быть совместимым, поэтому убедитесь, что вы проверяете свой 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 );

Подожди сек, почему нет там? Ну, есть некоторые форматы, у которых нет метаданных, а CGImageource не поддерживает, но это допустимые изображения. Пример - это изображения Pict Style Pict.

Теперь у нас есть Cgimageourceref, убедитесь, что это не ноль, а затем давайте теперь получим cgimedeStinationrineRef. Ух ты все эти ссылки отслеживают. До сих пор мы в 2!

Мы будем использовать эту функцию: cgimedeStinationscreatewithdata ()

  • 1-й параметр - ваши imagedata (zt cfmutabledataref)
  • 2-й параметр - ваш выходной uti, запомните список выше. (например, Kuttypepng)
  • 3-й параметр - это подсчет изображений для сохранения. Для одиночных файлов изображений это 1, в противном случае вы можете просто использовать следующее:

    Cgimageourcegetcount (imagesource);

  • 4-й параметр - это ноль.

Убедитесь, что есть ли у вас этот cgimedeStinationRef и теперь давайте добавим наши изображения из источника в него ... Это также будет включать в себя любые / все метаданные и сохранить разрешение.

Для нескольких изображений мы петли:

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

Для одного изображения это одна строка кода при индексе 0:

CGImageDestinationAddImageFromSource( imageDest, imageSource, 0, nil);

ОК, доработайте его, что пишет его на диск или контейнер для данных:

CGImageDestinationFinalize( imageDest );

Таким образом, что применные данные с самого начала есть все наши данные изображения и метаданные в нем сейчас.

Мы уже сделали? Почти, даже с сборкой мусора, вы должны убирать! Помните, что два Ref's One для источника и один для пункта назначения, так что сделайте 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? Это еще на другой день, но в результате вы сначала релизера размера ...

  1. Создать контекст с новым размером: cgbitmapcontextcreate ()
  2. Получить изображение Ref из индекса: cgimageourcecreateiMageatindex ()
  3. Получить копию метаданных: cgimageourcecopypropertiesatindex ()
  4. Нарисуйте изображение в контекст: CGCONTEXTDRAWIMAGE ()
  5. Получить измененное изображение из контекста: cgbitmapcontextcreateimage ()
  6. Теперь добавьте изображение и метаданные в DED REF: CGIMADESTICINATICADDDIMAGE ()

Промыть и повторите для нескольких изображений, встроенных в источник.

Единственное различие между ICO и ICNS - это то, что одно изображение, в то время как другой - это несколько изображений в одном файле. Ставка вы можете догадаться, что это?! ;-) Для этих форматов вам нужно уменьшить размер до определенного размера, в противном случае ошибка. Процесс, хотя это точно так же, где вы используете правильный UTI, но изменение изменений немного более строго.

Хорошо, надеюсь, это помогает другим там, и вы так же полны, как я сейчас!

OPPS, забыл упомянуть. Когда вы получите объект NSDATA, как вы хотите, например, WriteToFile, Writetourl или HEC, создайте еще один NSImage, если хотите.

Счастливое кодирование!

Сохранить как 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
        }
    }
}

Swift 4.2 Решение

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

Просто еще один гарантировал работу подхода, используя SWIFT:

У меня есть «изображение хорошо», где пользователю может бросить любое изображение. И этот «образ хорошо» имеет свойство изображения (типа 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)
}

В 1-й строке данного кода мы проверяем, есть ли наш образ хорошо.

В 2-й строке мы сделаем растровое изображение этого изображения.

В 3-й строке мы преобразуем наше битовое представление в тип JPG с фактором сжатия, установленным на «1» (без сжатия).

В 4-й линии мы сохраняем данные JPG с данным путем. «Атомарно: True» означает, что файл сохраняется как один кусок, и это гарантирует нас, что операция будет успешной.

NB: Вы можете использовать другой NSBitMapimageFileType в 3-й строке, чтобы сохранить свое изображение в другой формат. У него много:

NSBitmapImageFileType.NSBMPFileType
NSBitmapImageFileType.NSGIFFileType
NSBitmapImageFileType.NSPNGFileType

и т.п.

Чтобы помочь с кроссплатформенным кодом, я реализовал версиюUIImagePNGRepresentation() который работает на Mac (и использует 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

Применение:

if let data = UIImagePNGRepresentation(myImage) {
    do { try data.write(to: url, options: [.atomic]) }
    catch let error { print("Error writing image (\(error))") }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top