如何将 NSImage 保存为新文件
如何将 NSImage 保存为某个目录中的新文件(png、jpg、...)?
How can I save a NSImage as a new file (png, jpg, ...) in a certain directory?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
您可以像这样向 NSImage 添加一个类别。
对“TIFFRepresentation”的调用至关重要,否则您可能无法获得有效的图像。
You could add a category to NSImage like this
The call to "TIFFRepresentation" is essential otherwise you may not get a valid image.
做这样的事情:
Do something like this:
不知道你们其他人怎么样,但我更喜欢吃完整的玉米卷饼。上面描述的内容是可行的,没有任何问题,但我发现遗漏了一些东西。在这里我将强调我的观察:
即使图像分辨率大于该值。所以你输了
分辨率
PDF。来吧,尝试一个动画 GIF,你会发现动画丢失了。
因此,如果您想转换该图像,您真的想失去所有这些吗?
如果你想吃饱饭,那么让我们继续读下去……
有时,我的意思是,有时没有什么比好的老式学校发展更好的了。是的,这意味着我们必须做一些工作!
让我们开始吧:
我在 NSData 中创建一个类别。这些是类方法,因为您希望这些东西是线程安全的,并且没有什么比将您的东西放在堆栈上更安全的了。有两种方法,一种用于非多页图像的输出,一种用于多页图像的输出。
单个图像列表: JPG、PNG、BMP、JPEG-2000
多个图像列表: PDF、GIF、TIFF
首先在内存中创建一个可变数据空间。
其次获取 CGImageSourceRef。是的,听起来已经很丑了不是吗?这并没有那么糟糕,让我们继续...您确实想要源图像而不是表示或 NSImage 数据块。但是,我们确实有一个小问题。源可能不兼容,因此请确保根据 CGImageSourceCopyTypeIdentifiers() 中列出的内容检查您的 UTI
一些代码:
等一下,为什么 NSImage 在那里?有些格式没有元数据,CGImageSource 也不支持,但这些是有效的图像。一个例子是旧式 PICT 图像。
现在我们有了一个 CGImageSourceRef,确保它不为零,然后让我们得到一个 CGImageDestinationRef。哇,所有这些参考文献都需要跟踪。到目前为止我们是 2!
我们将使用这个函数: CGImageDestinationCreateWithData()
kUTTypePNG)
第三个参数是要保存的图像数量。对于单个图像文件来说
是 1 否则你可以简单地使用以下内容:
CGImageSourceGetCount( imageSource );
第四个参数为零。
检查您是否有此 CGImageDestinationRef,现在让我们将源中的图像添加到其中...这还将包括任何/所有元数据并保留分辨率。
对于多个图像,我们循环:
对于单个图像,它是索引 0 处的一行代码:
好的,完成它,将其写入磁盘或数据容器:
这样,可变数据从一开始就包含了我们所有的图像数据和元数据。
我们完成了吗?几乎,即使有垃圾收集,你也必须清理!
记住两个 Ref,一个用于源,一个用于目标,因此执行 CFRelease()
现在我们完成了,您最终得到的是一个转换后的图像,保留其所有元数据、分辨率等...
我的 NSData 类别方法看起来像this:
调整大小或 ICO / ICNS 怎么样?
这是另一天的内容,但总而言之,您首先要解决调整大小问题...
冲洗并重复嵌入源中的多个图像。
ICO 和 ICNS 之间的唯一区别是,一个是单个图像,而另一个是一个文件中的多个图像。我打赌你能猜出哪个是哪个?! ;-)
对于这些格式,您必须将大小调整到特定大小,否则会出现错误。
该过程与使用正确的 UTI 的过程完全相同,但调整大小更严格一些。
好吧,希望这可以帮助其他人,并且你和我现在一样饱!
哎呀,忘记说了。当你获得 NSData 对象时,可以按照你想要的方式使用它,例如 writeToFile、writeToURL,或者如果你愿意的话,创建另一个 NSImage。
快乐编码!
Not sure about the rest of you, but I prefer eating my full enchilada. What is described above will work and nothing is wrong with it, but I found a few things left out. Here I will highlight my observations:
even if the image resolution is greater than that. So you are losing
resolution
PDFs. Go ahead, try an animated GIF, you will find the animation lost
So if you want to convert that image, do you really want to lose out on all of this?
If you wish to eat your full meal, then lets read on...
Sometimes and I do mean sometimes there is nothing better than good ole old school development. Yeah that means we have to do a bit of work!
Let's get started:
I create a category in NSData. These are class methods because you want these things to be thread safe and there is nothing safer than putting your stuff on the stack. There are two types of methods, one for the output of non-multi-page images and one for the output of multi-page images.
List of single images: JPG, PNG, BMP, JPEG-2000
List of multiple images: PDF, GIF, TIFF
First create a mutable data space in memory.
Second get a CGImageSourceRef. Yeah sounding ugly already isn't it. It's not that bad, let's keep going... You really want the source image not a representation or NSImage chunk of data. However, we do have a small issue. The source might not be compatible, so make sure you check your UTI against those listed from CGImageSourceCopyTypeIdentifiers()
Some code:
Wait a sec, why is NSImage there? Well there are some formats that don't have metadata and CGImageSource does not support, but these are valid images. An example is old style PICT images.
Now we have a CGImageSourceRef, make sure it's not nil and then let's now get a CGImageDestinationRef. Wow all these ref's to keep track of. So far we are at 2!
We will use this function: CGImageDestinationCreateWithData()
kUTTypePNG)
3rd Param is the count of images to save. For single image files this
is 1 otherwise you can simply use the following:
CGImageSourceGetCount( imageSource );
4th Param is nil.
Check to see if you have this CGImageDestinationRef and now let's add our images from the source into it...this will also include any/all metadata and retain the resolution.
For multiple images we loop:
For single image it's one line of code at index 0:
Ok, finalize it which writes it to disk or data container:
So that Mutable Data from the beginning has all of our image data and metadata in it now.
Are we done yet? Almost, even with garbage collection you have to clean-up!
Remember two Ref's one for the source and one for the destination so do a CFRelease()
Now we are done and what you end up with is a converted image retaining all of its metadata, resolution, etc...
My NSData category methods look like this:
What about resizing or ICO / ICNS?
This is for another day, but in summary you first tackle resizing...
Rinse and repeat for multiple-images embedded in the source.
The only difference between an ICO and ICNS is that one is a single image while the other one is multiple-images in one file. Bet you can guess which is which?! ;-)
For these formats you have to resize down to a particular size otherwise ERROR will ensue.
The process though is exactly the same where you use the proper UTI, but the resizing is a bit more strict.
Ok hope this helps others out there and you are as full as I am now!
Opps, forgot to mention. When you get the NSData object do as you want with it such as writeToFile, writeToURL, or heck create another NSImage if you want.
Happy coding!
使用 swift3 另存为 PNG
save as PNG using swift3
Swift 4.2 解决方案
Swift 4.2 Solution
斯威夫特风格:
Swift Style:
为了帮助跨平台代码,我实现了一个在 Mac 上运行的
UIImagePNGRepresentation()
版本(并使用NSImage
)。用法:
To help with cross-platform code, I implemented a version of
UIImagePNGRepresentation()
that runs on Mac (and usesNSImage
).Usage:
带压缩和不带压缩的目标解决方案
Objc solution with and without compression
使用 SWIFT 的另一种保证有效的方法是:
我有一个“Image Well”,用户可以在其中放置任何图像。这个“Image Well”有一个通过插座访问的图像属性(NSImage 类型):
保存该图像的代码(您可以将其放在按钮操作中)是:
在给定代码的第一行中,我们检查我们是否图像 井有一个图像。
在第二行中,我们制作该图像的位图表示。
在第三行中,我们将 BitmapRepresentation 转换为 JPG 类型,并将压缩因子设置为“1”(无压缩)。
在第 4 行中,我们使用给定路径保存 JPG 数据。 “atomically: true”意味着文件被保存为一个整体,这确保我们操作将会成功。
注意:您可以在第三行中使用另一个 NSBitmapImageFileType,将图像保存为其他格式。它有很多:
等等。
Just one more guaranteed to work approach using SWIFT:
I have an "Image Well" where to user can drop any image. And this "Image Well" has an image property (of type NSImage) accessed via outlet:
And the code that saves this image (you can put it inside the button action) is:
In the 1st line of the given code we check if our Image Well has an image.
In the 2nd line we make a bitmap representation of that image.
In the 3rd line we convert our BitmapRepresentation to a JPG type with a compression factor set to "1" (no compression).
In the 4th line we save the JPG data with a given path. "atomically: true" means that the file is saved as one piece and that assures us that the operation will be successfull.
N.B.: You can use another NSBitmapImageFileType in the 3rd line, to save your image to another format. It has plenty:
etc.