Desenhe o NSIMage padrão invertido (branco em vez de preto)
-
22-09-2019 - |
Pergunta
Estou tentando desenhar um nsimage padrão em branco em vez de preto. O seguinte funciona bem para desenhar a imagem em preto no atual nsgraphicsContext:
NSImage* image = [NSImage imageNamed:NSImageNameEnterFullScreenTemplate];
[image drawInRect:r fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
Eu esperava que o NSCOMPOSTEXOR fizesse o truque, mas não. Preciso descer o complicado caminho do [Cifilter FilterWithName:@"Cicolorinvert"]? Sinto que devo estar perdendo algo simples.
Anders
Solução
A rota da imagem principal seria a mais confiável. Na verdade, não é muito complicado, eu publiquei uma amostra abaixo. Se você souber que nenhuma das suas imagens será invertida, poderá remover o código de transformação. A principal coisa a ser cuidadosa é que a conversão de NSImage
para CIImage
pode ser caro em termos de desempenho, para garantir que você cache o CIImage
Se possível, e não o recrie durante cada operação de desenho.
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];
Nota: Release/reter o gerenciamento da memória é deixado como um exercício, o código acima assume a coleta de lixo.
Se você deseja renderizar a imagem em um tamanho arbitrário, você pode fazer o seguinte:
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]];
Outras dicas
Apenas uma observação: descobri que o filtro cicolorinvert nem sempre é confiável. Por exemplo, se você deseja inverter uma imagem invertida no Photoshop, o cifilter produzirá uma imagem muito mais leve. Até onde eu entendi, isso acontece devido às diferenças no valor gama do cifilter (gama é 1) e imagens que vieram de outras fontes.
Enquanto procurava maneiras de alterar o valor gama para o Cifilter, encontrei uma nota de que há um bug no Cicontext: alterando seu valor gama do padrão 1 produzirá resultados imprevisíveis.
Independentemente disso, há outra solução para inverter o NSImage, que sempre produz os resultados corretos - invertendo pixels de nsbitmapimagerep.
Estou repositando o código de 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];