如何将 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。所以你失去了解决方案
  • 第二,多页面的图像,例如动画gif或pdf中的图像。来吧,尝试一下GIF动画,你会发现动画丢失了
  • 最后,所有元数据(例如 EXIF、GPS 等)都将丢失。

因此,如果您想转换该图像,您真的想失去所有这些吗?如果您想吃饱饭,那么让我们继续阅读......

有时,我的意思是,有时没有什么比好的老式学校开发更好的了。是的,这意味着我们必须做一些工作!

让我们开始吧:

我在 NSData 中创建一个类别。这些是类方法,因为您希望这些东西是线程安全的,并且没有什么比将您的东西放在堆栈上更安全的了。有两种方法,一种用于非多页图像的输出,一种用于多页图像的输出。

单张图片列表: JPG、PNG、BMP、JPEG-2000

多张图片列表: PDF、GIF、TIFF

首先在内存中创建一个可变数据空间。

NSMutableData * imageData    = [NSMutableData data];

其次获取 CGImageSourceRef。是的,听起来已经很丑了不是吗?事情并没有那么糟糕,我们继续吧……您确实想要源图像而不是表示形式或 NSImage 数据块。但是,我们确实有一个小问题。源可能不兼容,因此请确保根据 CGImageSourceCopyTypeIdentifiers() 列出的内容检查您的 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,确保它不为零,然后让我们得到一个 CGImageDestinationRef。哇,所有这些参考文献都需要跟踪。到目前为止我们是2!

我们将使用这个函数:CGImageDestinationCreateWithData()

  • 第一个参数是你的 imageData (cast CFMutableDataRef)
  • 第二个参数是你的输出 UTI,记住上面的列表。(例如。kUT类型PNG)
  • 第三个参数是要保存的图像数量。对于单个图像文件,这是1个,否则您只需使用以下内容:

    CGImageSourceGetCount( 图像源 );

  • 第四个参数为零。

检查您是否有此 CGImageDestinationRef,现在让我们将源中的图像添加到其中...这还将包括任何/所有元数据并保留分辨率。

对于多个图像,我们循环:

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

对于单个图像,它是索引 0 处的一行代码:

CGImageDestinationAddImageFromSource( imageDest, imageSource, 0, nil);

好的,完成它,将其写入磁盘或数据容器:

CGImageDestinationFinalize( imageDest );

因此,可变数据从一开始就包含了我们所有的图像数据和元数据。

我们完成了吗?几乎,即使有垃圾收集,你也必须清理!记住两个 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 之间的唯一区别是,一个是单个图像,而另一个是一个文件中的多个图像。我打赌你能猜出哪个是哪个?!;-)对于这些格式,您必须调整到特定尺寸的大小,否则会发生错误。该过程与使用正确的 UTI 的过程完全相同,但调整大小更严格一些。

好吧,希望这能帮助其他人,你也和我现在一样饱了!

哎呀,忘记说了。当你获取 NSData 对象时,可以按照你想要的方式使用它,例如 writeToFile、writeToURL,或者如果你愿意的话,创建另一个 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
        }
    }
}

<强>夫特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)")
        }
    }
}

夫特风格:

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

在给定的代码的第一行我们检查,如果我们的图像池具有图像。

在第二行,我们使该图像的位图表示。

在第三行中,我们提供了BitmapRepresentation转换为JPG类型与压缩系数设定为“1”(无压缩)。

在第四线我们保存在一个给定的路径中的JPG数据。 “原子:真”表示该文件保存为单件,并且使我们确信该操作将是全成

N.B:您可以使用另一种NSBitmapImageFileType在第3行,将图像保存为另一种格式。它有足够:

NSBitmapImageFileType.NSBMPFileType
NSBitmapImageFileType.NSGIFFileType
NSBitmapImageFileType.NSPNGFileType

要与跨平台的代码的帮助,我实现一个版本ofUIImagePNGRepresentation()在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