NSImage를 새 파일로 저장하는 방법
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가 있고, nil이 아닌지 확인한 다음 CGImageDestinationRef를 가져옵니다. 이 모든 심판이 추적해야합니다. 지금까지 우리는 2입니다!
이 함수를 사용합니다 : CGImageDestinationCreateWithData ()
- 첫 번째 매개 변수는 imageData입니다 (Cast CFMutableDataRef).
- 2nd Param은 출력 UTI입니다. 위의 목록을 기억하십시오. (예 : kUTTypePNG)
3rd Param은 저장할 이미지의 수입니다. 단일 이미지 파일의 경우 1이고 그렇지 않으면 다음을 사용할 수 있습니다.
CGImageSourceGetCount (이미지 소스);
4 번째 Param은 nil입니다.
이 CGImageDestinationRef가 있는지 확인하고 이제 소스의 이미지를 여기에 추가해 보겠습니다. 이것은 또한 모든 / 모든 메타 데이터를 포함하고 해상도를 유지합니다.
여러 이미지의 경우 루프 :
for ( NSUInteger i = 0; i < count; ++i )
CGImageDestinationAddImageFromSource( imageDest, imageSource, i, nil );
단일 이미지의 경우 인덱스 0에있는 코드 한 줄입니다.
CGImageDestinationAddImageFromSource( imageDest, imageSource, 0, nil);
좋아, 디스크 또는 데이터 컨테이너에 쓰는 것을 마무리하십시오.
CGImageDestinationFinalize( imageDest );
따라서 처음부터 Mutable Data에는 이제 모든 이미지 데이터와 메타 데이터가 포함됩니다.
아직 끝났어? 거의 가비지 컬렉션을 사용하더라도 정리해야합니다! 소스와 대상에 대한 두 개의 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는 어떻습니까? 이것은 다른 날에 대한 것이지만 요약하면 먼저 크기 조정을 시작합니다.
- 새 크기로 컨텍스트 만들기 : CGBitmapContextCreate ()
- 인덱스에서 이미지 참조 가져 오기 : CGImageSourceCreateImageAtIndex ()
- 메타 데이터 사본 가져 오기 : CGImageSourceCopyPropertiesAtIndex ()
- 컨텍스트에 이미지를 그립니다. CGContextDrawImage ()
- 컨텍스트에서 크기 조정 된 이미지 가져 오기 : CGBitmapContextCreateImage ()
- 이제 이미지와 메타 데이터를 Dest Ref : CGImageDestinationAddImage ()에 추가합니다.
소스에 포함 된 여러 이미지에 대해 헹구고 반복합니다.
ICO와 ICNS의 유일한 차이점은 하나는 단일 이미지이고 다른 하나는 하나의 파일에 여러 이미지라는 것입니다. 어느 쪽인지 짐작할 수 있겠습니까?! ;-) 이러한 형식의 경우 특정 크기로 크기를 조정해야합니다. 그렇지 않으면 ERROR가 발생합니다. 하지만 프로세스는 적절한 UTI를 사용하는 곳과 정확히 동일하지만 크기 조정은 조금 더 엄격합니다.
좋아, 이것이 다른 사람들에게 도움이 되었기를 바랍니다. 그리고 당신은 지금처럼 가득 차 있습니다!
언급하는 것을 잊었습니다. NSData 객체를 얻으면 writeToFile, writeToURL과 같이 원하는대로 수행하거나 원하는 경우 다른 NSImage를 만듭니다.
즐거운 코딩 되세요!
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
}
}
}
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)")
}
}
}
스위프트 스타일 :
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를 사용하여 작업을 보장하는 한 가지 더 :
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:
@IBOutlet weak var imageWell: NSImageView!
And the code that saves this image (you can put it inside the button action) is:
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)
}
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:
NSBitmapImageFileType.NSBMPFileType
NSBitmapImageFileType.NSGIFFileType
NSBitmapImageFileType.NSPNGFileType
etc.
To help with cross-platform code, I implemented a version ofUIImagePNGRepresentation()
that runs on Mac (and uses 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
Usage:
if let data = UIImagePNGRepresentation(myImage) {
do { try data.write(to: url, options: [.atomic]) }
catch let error { print("Error writing image (\(error))") }
}
참고URL : https://stackoverflow.com/questions/3038820/how-to-save-a-nsimage-as-a-new-file
'developer tip' 카테고리의 다른 글
td 너비, 작동하지 않습니까? (0) | 2020.10.26 |
---|---|
Android ArrayList of custom objects-Save to SharedPreferences-Serializable? (0) | 2020.10.25 |
UITableView : 빈 섹션에서 헤더 숨기기 (0) | 2020.10.25 |
NSDate에 한 달을 추가하는 방법은 무엇입니까? (0) | 2020.10.25 |
Android ImageView 크기가 소스 이미지로 확장되지 않음 (0) | 2020.10.25 |