Как изменить размер NSImage?
У меня есть NSBitmapImageRep
размером W
x H
.
Я создаю NSImage
и вызываю addRepresentation:
. Затем мне нужно изменить размер NSImage
.
Я попробовал метод setSize
, но он не работает. Что я должен делать?
Ответы
Ответ 1
Изменить:
Поскольку этот ответ все еще является принятым, но был написан без учета экранов Retina, я приведу ссылку на лучшее решение далее по теме: Objective-C Swift4
Поскольку метод Paresh является полностью правильным, но не рекомендуется с 10.8, я выложу рабочий код 10.8 ниже. Все заслуги Пареша, хотя ответ.
- (NSImage *)imageResize:(NSImage*)anImage newSize:(NSSize)newSize {
NSImage *sourceImage = anImage;
[sourceImage setScalesWhenResized:YES];
// Report an error if the source isn't a valid image
if (![sourceImage isValid]){
NSLog(@"Invalid Image");
} else {
NSImage *smallImage = [[NSImage alloc] initWithSize: newSize];
[smallImage lockFocus];
[sourceImage setSize: newSize];
[[NSGraphicsContext currentContext] setImageInterpolation:NSImageInterpolationHigh];
[sourceImage drawAtPoint:NSZeroPoint fromRect:CGRectMake(0, 0, newSize.width, newSize.height) operation:NSCompositeCopy fraction:1.0];
[smallImage unlockFocus];
return smallImage;
}
return nil;
}
Ответ 2
Ответ Томаса Йоханнесмайера с помощью lockFocus
не работает так, как вы можете предполагать на экранах Retina/HiDPI: он изменяет размеры до желаемых точек в собственном масштабе экрана, а не пикселей.
- Если вы изменяете размер экрана на экране, используйте этот метод.
- Если вы изменяете размер файла с точными размерами пикселей, он будет в два раза больше при работе на экранах Retina (2x DPI).
Этот метод, собранный из разных ответов, включая некоторые из этого связанного вопроса, изменяет размеры до указанных размеров пикселей независимо от текущего экрана DPI
+ (NSImage *)resizedImage:(NSImage *)sourceImage toPixelDimensions:(NSSize)newSize
{
if (! sourceImage.isValid) return nil;
NSBitmapImageRep *rep = [[NSBitmapImageRep alloc]
initWithBitmapDataPlanes:NULL
pixelsWide:newSize.width
pixelsHigh:newSize.height
bitsPerSample:8
samplesPerPixel:4
hasAlpha:YES
isPlanar:NO
colorSpaceName:NSCalibratedRGBColorSpace
bytesPerRow:0
bitsPerPixel:0];
rep.size = newSize;
[NSGraphicsContext saveGraphicsState];
[NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:rep]];
[sourceImage drawInRect:NSMakeRect(0, 0, newSize.width, newSize.height) fromRect:NSZeroRect operation:NSCompositeCopy fraction:1.0];
[NSGraphicsContext restoreGraphicsState];
NSImage *newImage = [[NSImage alloc] initWithSize:newSize];
[newImage addRepresentation:rep];
return newImage;
}
Ответ 3
EDIT Вы можете изменить размер изображения, используя следующую функцию:
- (NSImage *)imageResize:(NSImage*)anImage
newSize:(NSSize)newSize
{
NSImage *sourceImage = anImage;
[sourceImage setScalesWhenResized:YES];
// Report an error if the source isn't a valid image
if (![sourceImage isValid])
{
NSLog(@"Invalid Image");
} else
{
NSImage *smallImage = [[[NSImage alloc] initWithSize: newSize] autorelease];
[smallImage lockFocus];
[sourceImage setSize: newSize];
[[NSGraphicsContext currentContext] setImageInterpolation:NSImageInterpolationHigh];
[sourceImage compositeToPoint:NSZeroPoint operation:NSCompositeCopy];
[smallImage unlockFocus];
return smallImage;
}
return nil;
}
Во-вторых, вот так:
NSData *imageData = [yourImg TIFFRepresentation]; // converting img into data
NSBitmapImageRep *imageRep = [NSBitmapImageRep imageRepWithData:imageData]; // converting into BitmapImageRep
NSDictionary *imageProps = [NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:0.9] forKey:NSImageCompressionFactor]; // any number betwwen 0 to 1
imageData = [imageRep representationUsingType:NSJPEGFileType properties:imageProps]; // use NSPNGFileType if needed
NSImage *resizedImage = [[NSImage alloc] initWithData:imageData]; // image created from data
Ответ 4
На самом деле нет необходимости изменять какие-либо параметры исходного изображения, такие как size
. Следующий фрагмент уже есть в Swift, но я думаю, что из него можно сделать вывод версии Objective-C:
func resized(to: CGSize) -> NSImage {
let img = NSImage(size: to)
img.lockFocus()
defer {
img.unlockFocus()
}
if let ctx = NSGraphicsContext.current {
ctx.imageInterpolation = .high
draw(in: NSRect(origin: .zero, size: to),
from: NSRect(origin: .zero, size: size),
operation: .copy,
fraction: 1)
}
return img
}
Ответ 5
@Марко ответ написан на Swift 4:
extension NSImage {
func resized(to newSize: NSSize) -> NSImage? {
if let bitmapRep = NSBitmapImageRep(
bitmapDataPlanes: nil, pixelsWide: Int(newSize.width), pixelsHigh: Int(newSize.height),
bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false,
colorSpaceName: .calibratedRGB, bytesPerRow: 0, bitsPerPixel: 0
) {
bitmapRep.size = newSize
NSGraphicsContext.saveGraphicsState()
NSGraphicsContext.current = NSGraphicsContext(bitmapImageRep: bitmapRep)
draw(in: NSRect(x: 0, y: 0, width: newSize.width, height: newSize.height), from: .zero, operation: .copy, fraction: 1.0)
NSGraphicsContext.restoreGraphicsState()
let resizedImage = NSImage(size: newSize)
resizedImage.addRepresentation(bitmapRep)
return resizedImage
}
return nil
}
}
let targetSize = NSSize(width: 256.0, height: 256.0)
let newImageResized = myimage.resized(to: targetSize)
Ответ 6
Вот Swift 4 версия ответа Томаса Йоханнесмейера:
func resize(image: NSImage, w: Int, h: Int) -> NSImage {
var destSize = NSMakeSize(CGFloat(w), CGFloat(h))
var newImage = NSImage(size: destSize)
newImage.lockFocus()
image.draw(in: NSMakeRect(0, 0, destSize.width, destSize.height), from: NSMakeRect(0, 0, image.size.width, image.size.height), operation: NSCompositingOperation.sourceOver, fraction: CGFloat(1))
newImage.unlockFocus()
newImage.size = destSize
return NSImage(data: newImage.tiffRepresentation!)!
}
И Свифт 4 версия Марко отвечает:
func resize(image: NSImage, w: Int, h: Int) -> NSImage {
let destSize = NSMakeSize(CGFloat(w), CGFloat(h))
let rep = NSBitmapImageRep(bitmapDataPlanes: nil, pixelsWide: Int(destSize.width), pixelsHigh: Int(destSize.height), bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false, colorSpaceName: .calibratedRGB, bytesPerRow: 0, bitsPerPixel: 0)
rep?.size = destSize
NSGraphicsContext.saveGraphicsState()
if let aRep = rep {
NSGraphicsContext.current = NSGraphicsContext(bitmapImageRep: aRep)
}
image.draw(in: NSMakeRect(0, 0, destSize.width, destSize.height), from: NSZeroRect, operation: NSCompositingOperation.copy, fraction: 1.0)
NSGraphicsContext.restoreGraphicsState()
let newImage = NSImage(size: destSize)
if let aRep = rep {
newImage.addRepresentation(aRep)
}
return newImage
}
Ответ 7
Полный ответ Swift 3 (измененный от @Erik Aigner выше):
extension NSImage {
func resizeImage(width: CGFloat, _ height: CGFloat) -> NSImage {
let img = NSImage(size: CGSize(width:width, height:height))
img.lockFocus()
let ctx = NSGraphicsContext.current()
ctx?.imageInterpolation = .high
self.draw(in: NSMakeRect(0, 0, width, height), from: NSMakeRect(0, 0, size.width, size.height), operation: .copy, fraction: 1)
img.unlockFocus()
return img
}
}
Ответ 8
Ниже приведено соотношение между сохранением версии версии 5, просто установите MinimumSize как минимальную высоту или ширину, которые вы хотите:
func imageResized(image: NSImage) -> NSImage {
let ratio = image.size.height / image.size.width
let width: CGFloat
let height: CGFloat
// We keep ratio of image
if ratio > 1 {
width = minimumSize
height = minimumSize * ratio
} else {
width = minimumSize
height = minimumSize * (1 / ratio)
}
let destSize = NSSize(width: width, height: height)
let newImage = NSImage(size: destSize)
newImage.lockFocus()
image.draw(in: NSRect(x: 0, y: 0, width: destSize.width, height: destSize.height), from: NSRect(x: 0, y: 0, width: image.size.width, height: image.size.height), operation: .sourceOver, fraction: 1.0)
newImage.unlockFocus()
newImage.size = destSize
return NSImage(data: newImage.tiffRepresentation!)!
}
Ответ 9
Для простого масштабирования NSBitmapImageRep
static NSBitmapImageRep *i_scale_bitmap(const NSBitmapImageRep *bitmap, const uint32_t width, const uint32_t height)
{
NSBitmapImageRep *new_bitmap = NULL;
CGImageRef dest_image = NULL;
CGColorSpaceRef space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
CGContextRef context = CGBitmapContextCreate(NULL, (size_t)width, (size_t)height, PARAM(bitsPerComponent, 8), PARAM(bytesPerRow, (size_t)(width * 4)), space, kCGImageAlphaPremultipliedLast);
CGImageRef src_image = [bitmap CGImage];
CGRect rect = CGRectMake((CGFloat)0.f, (CGFloat)0.f, (CGFloat)width, (CGFloat)height);
CGContextDrawImage(context, rect, src_image);
dest_image = CGBitmapContextCreateImage(context);
CGContextRelease(context);
CGColorSpaceRelease(space);
new_bitmap = [[NSBitmapImageRep alloc] initWithCGImage:dest_image];
CGImageRelease(dest_image);
return new_bitmap;
}
И для масштабирования NSImage на основе NSBitmapImageRep
ImageImp *imgimp_create_scaled(const ImageImp *image, const uint32_t new_width, const uint32_t new_height)
{
NSImage *src_image = (NSImage*)image;
NSBitmapImageRep *src_bitmap, *dest_bitmap;
NSImage *scaled_image = nil;
cassert_no_null(src_image);
cassert([[src_image representations] count] == 1);
cassert([[[src_image representations] objectAtIndex:0] isKindOfClass:[NSBitmapImageRep class]]);
src_bitmap = (NSBitmapImageRep*)[[(NSImage*)image representations] objectAtIndex:0];
cassert_no_null(src_bitmap);
dest_bitmap = i_scale_bitmap(src_bitmap, new_width, new_height);
scaled_image = [[NSImage alloc] initWithSize:NSMakeSize((CGFloat)new_width, (CGFloat)new_height)];
[scaled_image addRepresentation:dest_bitmap];
cassert([scaled_image retainCount] == 1);
[dest_bitmap release];
return (ImageImp*)scaled_image;
}
Рисование непосредственно над NSImage ([NSImage lockFocus] и т.д.) Создаст NSCGImageSnapshotRep, а не NSBitmapImageRep.