Нарисуйте инвертированный стандартный NSImage (белый вместо черного)
-
22-09-2019 - |
Вопрос
Я пытаюсь нарисовать стандартный NSImage белым, а не черным.Следующее отлично работает для рисования изображения черным в текущем NSGraphicsContext:
NSImage* image = [NSImage imageNamed:NSImageNameEnterFullScreenTemplate];
[image drawInRect:r fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
Я ожидал, что NSCompositeXOR сделает свое дело, но нет.Нужно ли мне идти по сложному пути [CIFilter filterWithName:@"CIColorInvert"]?Я чувствую, что мне не хватает чего-то простого.
Андерс
Решение
Маршрут Core Image будет самым надежным.На самом деле это не очень сложно, образец я разместил ниже.Если вы знаете, что ни одно из ваших изображений не будет перевернуто, вы можете удалить код преобразования.Главное, на что следует обратить внимание, это то, что преобразование из NSImage
к CIImage
может быть дорогостоящим с точки зрения производительности, поэтому вам следует убедиться, что вы кэшируете CIImage
если возможно, и не создавайте его заново во время каждой операции рисования.
CIImage* ciImage = [[CIImage alloc] initWithData:[yourImage TIFFRepresentation]];
if ([yourImage isFlipped])
{
CGRect cgRect = [ciImage extent];
CGAffineTransform transform;
transform = CGAffineTransformMakeTranslation(0.0,cgRect.size.height);
transform = CGAffineTransformScale(transform, 1.0, -1.0);
ciImage = [ciImage imageByApplyingTransform:transform];
}
CIFilter* filter = [CIFilter filterWithName:@"CIColorInvert"];
[filter setDefaults];
[filter setValue:ciImage forKey:@"inputImage"];
CIImage* output = [filter valueForKey:@"outputImage"];
[output drawAtPoint:NSZeroPoint fromRect:NSRectFromCGRect([output extent]) operation:NSCompositeSourceOver fraction:1.0];
Примечание:Управление освобождением/сохранением памяти оставлено в качестве упражнения, приведенный выше код предполагает сбор мусора.
Если вы хотите визуализировать изображение произвольного размера, вы можете сделать следующее:
NSSize imageSize = NSMakeSize(1024,768); //or whatever size you want
[yourImage setSize:imageSize];
[yourImage lockFocus];
NSBitmapImageRep* bitmap = [[NSBitmapImageRep alloc] initWithFocusedViewRect:NSMakeRect(0, 0, imageSize.width, imageSize.height)];
[yourImage unlockFocus];
CIImage* image = [CIImage imageWithData:[bitmap TIFFRepresentation]];
Другие советы
Только одно замечание:Я обнаружил, что фильтр CIColorInvert не всегда надежен.Например, если вы хотите инвертировать изображение, инвертированное в Photoshop, CIFilter создаст гораздо более светлое изображение.Насколько я понял, это происходит из-за различий в значении гаммы CIFilter (гамма равна 1) и изображений, полученных из других источников.
Пока я искал способы изменить значение гаммы для CIFilter, я нашел заметку о том, что в CIContext есть ошибка:изменение значения гаммы со значения по умолчанию 1 приведет к непредсказуемым результатам.
Тем не менее, есть еще одно решение инвертировать NSImage, которое всегда дает правильные результаты — путем инвертирования пикселей NSBitmapImageRep.
Перепечатываю код с etutorials.org (http://bit.ly/Y6GpLn):
// srcImageRep is the NSBitmapImageRep of the source image
int n = [srcImageRep bitsPerPixel] / 8; // Bytes per pixel
int w = [srcImageRep pixelsWide];
int h = [srcImageRep pixelsHigh];
int rowBytes = [srcImageRep bytesPerRow];
int i;
NSImage *destImage = [[NSImage alloc] initWithSize:NSMakeSize(w, h)];
NSBitmapImageRep *destImageRep = [[[NSBitmapImageRep alloc]
initWithBitmapDataPlanes:NULL
pixelsWide:w
pixelsHigh:h
bitsPerSample:8
samplesPerPixel:n
hasAlpha:[srcImageRep hasAlpha]
isPlanar:NO
colorSpaceName:[srcImageRep colorSpaceName]
bytesPerRow:rowBytes
bitsPerPixel:NULL] autorelease];
unsigned char *srcData = [srcImageRep bitmapData];
unsigned char *destData = [destImageRep bitmapData];
for ( i = 0; i < rowBytes * h; i++ )
*(destData + i) = 255 - *(srcData + i);
[destImage addRepresentation:destImageRep];