如何在特定目录中将NSImage保存为新文件(png,jpg,...)?
Answers:
做这样的事情:
NSBitmapImageRep *imgRep = [[image representations] objectAtIndex: 0];
NSData *data = [imgRep representationUsingType: NSPNGFileType properties: nil];
[data writeToFile: @"/path/to/file.png" atomically: NO];
[* representationUsingType:properties:]: unrecognized selector sent to instance
解决方法,请点击这里:NSCGImageSnapshotRep,如何获取bitmapData
您可以像这样向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”是必不可少的,否则您可能无法获得有效的图像。
不确定其余的人,但我更喜欢吃我的全麦卷饼。上面描述的内容将起作用,并且没有任何问题,但是我发现有一些遗漏之处。在这里,我将重点介绍我的观察:
因此,如果您要转换该图像,您是否真的想输掉所有这些?如果您想吃饱的饭,那么请继续阅读...
有时候,而且我确实表示有时候,没有什么比旧学校的良好发展更好。是的,这意味着我们需要做一些工作!
让我们开始吧:
我在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,确保它不是nil,然后让我们获取一个CGImageDestinationRef。哇,所有这些裁判都在跟踪。到目前为止,我们是2点!
我们将使用此函数:CGImageDestinationCreateWithData()
第三参数是要保存的图像数。对于单个图像文件,该值为1,否则您可以简单地使用以下命令:
CGImageSourceGetCount(imageSource);
第四参数为零。
检查是否有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怎么样?这是另一天,但总而言之,您首先要解决调整大小的问题...
冲洗并重复执行源中嵌入的多个图像。
ICO和ICNS的唯一区别是,一个文件是一个图像,而另一个文件是一个文件中的多个图像。打赌,你可以猜哪个是哪个?;-)对于这些格式,您必须将尺寸调整为特定的尺寸,否则将导致ERROR。尽管使用适当的UTI的过程完全相同,但是调整大小要严格一些。
好的,希望这对其他人有帮助,您和我一样充实!
对不起,忘了提。当您获得NSData对象时,可以根据需要使用它,例如writeToFile,writeToURL或根据需要创建另一个NSImage。
祝您编码愉快!
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)")
}
}
}
self.self
代替self
吗?有什么区别吗?
<<Class-Name> <Memory-Address>>
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
}
}
}
为了帮助跨平台代码,我实现了一个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))") }
}
使用SWIFT可以保证的另一种可行方法:
我有一个“图像井”,用户可以在其中放置任何图像。并且此“ Image Well”具有可通过出口访问的image属性(类型为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)
}
在给定代码的第一行中,我们检查Image Well是否有图像。
在第二行中,我们对该图像进行位图表示。
在第三行中,我们将BitmapRepresentation转换为JPG类型,其压缩系数设置为“ 1”(无压缩)。
在第四行中,我们以给定路径保存JPG数据。“ atomically:true”表示将文件保存为一个文件,这可以确保操作成功。
注意:您可以在第三行中使用另一个NSBitmapImageFileType,以将图像保存为另一种格式。它有很多:
NSBitmapImageFileType.NSBMPFileType
NSBitmapImageFileType.NSGIFFileType
NSBitmapImageFileType.NSPNGFileType
等等
带和不带压缩的Objc解决方案
NSImage* image;
// No compression
NSData* data = [image TIFFRepresentation];
// With compression
NSData* data = [image
TIFFRepresentationUsingCompression:NSTIFFCompressionLZW
factor:0.5f];
if (data != nil) {
NSBitmapImageRep* bitmap = [[NSBitmapImageRep alloc] initWithData:data];
if (bitmap != nil) {
NSData* bitmapData = [bitmap
representationUsingType:NSBitmapImageFileTypePNG
properties:@{}];
if (bitmapData != nil) {
[bitmapData
writeToFile:<file_path>
atomically:true];
}
}
}