NSImage在writeToFile上失去了质量

时间:2011-10-18 08:26:58

标签: objective-c cocoa nsimage

基本上,我正在尝试创建一个批量图像处理程序,它将调整每个图像的大小并在边缘周围添加边框(边框也将由图像组成)。虽然我还没有完成这个实现,但这超出了我的问题的范围,我会问它,因为即使我在这里得到了一个很好的答案,我仍然可能采取错误的方法来实现目标,并且任何帮助都能认识到这一点我将不胜感激。无论如何,这是我的问题:

问题: 我可以使用下面的现有代码并修改它以创建比当前输出的代码更高质量的图像保存到文件吗?我花了10多个小时试图弄清楚我做错了什么; “secondaryImage”将高质量的已调整大小的图像绘制到自定义视图中,但我尝试保存文件的所有内容都会导致图像质量显着降低(不像是像素化,只是明显更模糊)。最后,我在Apple的“Reducer”示例(在ImageReducer.m的末尾)中找到了一些代码,用于锁定焦点并从当前视图获取NSBitmapImageRep。这使得图像质量大幅增加,然而,Photoshop做同样事情的输出更清晰一点。看起来绘制到视图的图像质量与保存到文件的质量相同,因此两者都低于Photoshop的相同图像质量,大小调整为50%,就像这个一样。甚至可以获得比这更高质量的大小调整图像吗?

除此之外,如何修改现有代码才能控制保存到文件的图像质量?我可以改变压缩和像素密度吗?无论是修改我的代码还是指向好的示例或教程(最好是后者),我都会感激不尽。非常感谢!

- (void)drawRect:(NSRect)rect {

// Getting source image
NSImage *image = [[NSImage alloc] initWithContentsOfFile: @"/Users/TheUser/Desktop/4.jpg"];

// Setting NSRect, which is how resizing is done in this example. Is there a better way?
NSRect halfSizeRect = NSMakeRect(0, 0, image.size.width * 0.5, image.size.height * 0.5);

// Sort of used as an offscreen image or palate to do drawing onto; the future I will use to group several images into one.
NSImage *secondaryImage = [[NSImage alloc] initWithSize: halfSizeRect.size];
[secondaryImage lockFocus];

[[NSGraphicsContext currentContext] setImageInterpolation: NSImageInterpolationHigh];

[image drawInRect: halfSizeRect fromRect: NSZeroRect operation: NSCompositeSourceOver fraction: 1.0];

[secondaryImage unlockFocus];
[secondaryImage drawInRect: halfSizeRect fromRect: NSZeroRect   operation: NSCompositeSourceOver fraction: 1.0];

// Trying to add image quality options; does this usage even affect the final image?
NSBitmapImageRep *bip = nil;
bip = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL pixelsWide: secondaryImage.size.width pixelsHigh: secondaryImage.size.width bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES isPlanar:NO colorSpaceName:NSDeviceRGBColorSpace bytesPerRow:0 bitsPerPixel:0];

[secondaryImage addRepresentation: bip];

// Four lines below are from aforementioned "ImageReducer.m"
NSSize size = [secondaryImage size];
[secondaryImage lockFocus];
NSBitmapImageRep *bitmapImageRep = [[NSBitmapImageRep alloc] initWithFocusedViewRect:NSMakeRect(0, 0, size.width, size.height)];
[secondaryImage unlockFocus];

NSDictionary *prop = [NSDictionary dictionaryWithObject: [NSNumber numberWithFloat: 1.0] forKey: NSImageCompressionFactor];
NSData *outputData = [bitmapImageRep representationUsingType:NSJPEGFileType properties: prop];
[outputData writeToFile:@"/Users/TheUser/Desktop/4_halfsize.jpg" atomically:NO];

// release from memory
[image release];    
[secondaryImage release];
[bitmapImageRep release];
[bip release];
}

2 个答案:

答案 0 :(得分:0)

我不确定你为什么要在屏幕上徘徊。这可能会影响结果,而且不需要。

您可以使用CGImage和CGBitmapContext完成所有这些操作,使用生成的图像在需要时绘制到屏幕上。我已经使用了这些API并且效果很好(但我不知道它们与你当前的方法相比如何)。

另一个注意事项:以更高的质量渲染中间体,然后调整大小并减少到您编写的版本的8bpc。现在这不会产生显着差异,但一旦引入过滤,它就会(在大多数情况下)。

答案 1 :(得分:0)

最后,其中一个“啊哈!”时刻!我尝试在高质量的.tif文件上使用相同的代码,结果图像小8倍(尺寸),而不是我告诉它做的50%。当我尝试显示图像时,它会重新缩放图像,当它应该以相同的高度和宽度显示时,它仍然比原始图像小4倍。 我发现我从导入的图片中获取NSSize的方式是错误的。以前,它读取:

NSRect halfSizeRect = NSMakeRect(0, 0, image.size.width * 0.5, image.size.height * 0.5);

它应该在哪里:

NSBitmapImageRep *imageRep = [NSBitmapImageRep imageRepWithData: [image TIFFRepresentation]];
NSRect halfSizeRect = NSMakeRect(0, 0, [imageRep pixelsWide]/2, [imageRep pixelsHigh]/2);

显然它与DPI和爵士乐有关,所以我需要从BitmapImageRep而不是从image.size获得正确的大小。 通过这一改变,我能够以与Photoshop无法区分的质量进行保存。