web-dev-qa-db-ja.com

NSImageを新しいファイルとして保存する方法

NSImageを特定のディレクトリに新しいファイル(png、jpg、...)として保存するにはどうすればよいですか?

72
burki

このようなことをしてください:

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

このように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」の呼び出しは不可欠です。そうしないと、有効な画像を取得できない可能性があります。

161
Pegolon

あなたの残りの部分についてはわからないが、私は完全なエンチラーダを食べることを好む。上記で説明したことは機能し、何も問題はありませんが、いくつかの問題が残っています。ここで私の観察結果を強調します:

  • 最初に、画像解像度がそれよりも大きい場合でも72 DPIのように見える最適な表現が提供されます。あなたは解像度を失っています
  • 次に、アニメーションGIFやPDFのような複数ページの画像についてはどうでしょう。アニメーションGIFを試してください。アニメーションが失われます。
  • 最後に、EXIF、GPSなどのデータなどのデータはすべて失われます。

その画像を変換したい場合、本当にこれらすべてを失いたいですか?あなたが完全な食事を食べたいなら、読んでみましょう...

時々、私は時々、古き良きオールドスクールの開発よりも良いものはないことを意味します。ええ、それは私たちが少し仕事をしなければならないことを意味します!

始めましょう:

NSDataにカテゴリを作成します。これらはクラスメソッドです。これらのことをスレッドセーフにしたいので、スタックに置くよりも安全なものはないからです。メソッドには2つのタイプがあります。1つは非マルチページ画像の出力用、もう1つはマルチページ画像の出力用です。

単一画像のリスト: JPG、PNG、BMP、JPEG-2000

複数の画像のリスト: PDF、GIF、TIFF

まず、メモリ内に可変データスペースを作成します。

NSMutableData * imageData    = [NSMutableData data];

次に、CGImageSourceRefを取得します。うん、もういですね。それほど悪くはありません、続けましょう...データの表現やNSImageチャンクではなく、ソースイメージが本当に必要です。ただし、小さな問題があります。ソースには互換性がない可能性があるため、CGImageSourceCopyTypeIdentifiers()からリストされたUTIとUTIを必ず確認してください。

いくつかのコード:

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ができました。nilでないことを確認してから、CGImageDestinationRefを取得しましょう。これらすべての参照を追跡するのはすごい。これまでのところ、2になっています!

この関数を使用します:CGImageDestinationCreateWithData()

  • 最初のパラメーターは、imageData(キャストCFMutableDataRef)です
  • 2番目のパラメータは出力UTIです。上記のリストを思い出してください。 (例:kUTTypePNG)
  • 3番目のパラメータは、保存する画像の数です。単一の画像ファイルの場合、これは1です。それ以外の場合は、単に次を使用できます。

    CGImageSourceGetCount(imageSource);

  • 4番目のパラメーターはありません。

このCGImageDestinationRefがあるかどうかを確認し、ソースから画像を追加してみましょう...これには、すべて/すべてのメタデータが含まれ、解像度が保持されます。

複数の画像の場合、ループします:

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

単一の画像の場合、インデックス0の1行のコードです。

CGImageDestinationAddImageFromSource( imageDest, imageSource, 0, nil);

OK、ファイナライズしてディスクまたはデータコンテナーに書き込みます。

CGImageDestinationFinalize( imageDest );

そのため、最初からの可変データには、すべての画像データとメタデータが含まれています。

まだ終わってないか?ほとんど、ガベージコレクションを使用しても、クリーンアップする必要があります。参照元と送信先の2つの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はどうですか?これは別の日ですが、要約すると最初にサイズ変更に取り組みます...

  1. 新しいサイズでコンテキストを作成:CGBitmapContextCreate()
  2. インデックスから画像参照を取得します:CGImageSourceCreateImageAtIndex()
  3. メタデータのコピーを取得:CGImageSourceCopyPropertiesAtIndex()
  4. 画像をコンテキストに描画します:CGContextDrawImage()
  5. コンテキストからサイズ変更された画像を取得します:CGBitmapContextCreateImage()
  6. 次に、Dest Refに画像とメタデータを追加します:CGImageDestinationAddImage()

ソースに埋め込まれた複数の画像をすすぎ、繰り返します。

ICOとICNSの唯一の違いは、1つは単一のイメージであり、もう1つは1つのファイル内の複数のイメージであることです。どっちがどっちなのか推測できる?! ;-)これらのフォーマットでは、特定のサイズにサイズ変更する必要があります。そうしないと、エラーが発生します。ただし、プロセスは適切なUTIを使用する場合とまったく同じですが、サイズ変更はもう少し厳密です。

これが他の人の助けになり、あなたが今と同じくらいいっぱいになっていることを願っています!

おっと、言及するのを忘れました。 NSDataオブジェクトを取得したら、writeToFile、writeToURL、または必要に応じて別のNSImageを作成します。

ハッピーコーディング!

33
Arvin

swift3を使用してPNGとして保存する

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
        }
    }
}
14
neoneye

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

迅速なスタイル:

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

クロスプラットフォームコードを支援するために、Macで実行する(およびNSImageを使用する)バージョンのUIImagePNGRepresentation()を実装しました。

#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))") }
}
1
Robin Stewart

Swiftを使用した動作保証アプローチがもう1つあります。

ユーザーが任意の画像をドロップできる「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)
}

指定されたコードの1行目で、Image Wellに画像があるかどうかを確認します。

2行目では、その画像のビットマップ表現を作成します。

3行目では、BitmapRepresentationを、圧縮係数を「1」に設定したJPGタイプに変換します(圧縮なし)。

4行目では、指定されたパスでJPGデータを保存します。 「atomically:true」は、ファイルが1つのピースとして保存され、操作が成功することを保証することを意味します。

N.B.: 3行目の別のNSBitmapImageFileTypeを使用して、画像を別の形式で保存できます。たくさんあります:

NSBitmapImageFileType.NSBMPFileType
NSBitmapImageFileType.NSGIFFileType
NSBitmapImageFileType.NSPNGFileType

等.

1
German G.