Dibuje NSImage estándar invertido (blanco en lugar de negro)
-
22-09-2019 - |
Pregunta
Estoy tratando de dibujar una NSImage estándar en blanco en lugar de negro. El siguiente funciona bien para dibujar la imagen en negro en la corriente NSGraphicsContext:
NSImage* image = [NSImage imageNamed:NSImageNameEnterFullScreenTemplate];
[image drawInRect:r fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
Me esperaba NSCompositeXOR para hacer el truco, pero no. ¿Es necesario ir por el complicado [CIFilter filterWithName: @ "CIColorInvert"] camino? Siento que debo estar perdiendo algo simple.
Anders
Solución
La ruta Core Image sería el más fiable. En realidad no es muy complicado, he publicado una muestra a continuación. Si conoces a ninguno de sus imágenes se volcó entonces se puede eliminar el código de transformación. Lo principal a tener cuidado es que la conversión de NSImage
a CIImage
puede ser costoso en cuanto al rendimiento, por lo que debe asegurarse de guardar en caché el CIImage
si es posible y no es necesario volver a crearlo durante cada operación de trazado.
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:. Liberación / retener la gestión de memoria se deja como un ejercicio, el código anterior supone la recogida de basura
Si desea procesar la imagen en un tamaño arbitrario, se puede hacer lo siguiente:
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]];
Otros consejos
Sólo una nota: me encontré con que el filtro CIColorInvert no siempre es fiable. Por ejemplo, si desea invertir vuelta una imagen invertida en Photoshop, el CIFilter producirá una imagen mucho más ligero. Por lo que he entendido, sucede debido a las diferencias en el valor de gamma CIFilter (gamma es 1) y las imágenes que vienen de otras fuentes.
Mientras que estaba buscando maneras de cambiar el valor gamma de CIFilter, encontré una nota que hay un error en CIContext:. Cambiar su valor de gama del valor predeterminado 1 producirá resultados impredecibles
Independientemente, no hay otra solución para invertir NSImage, que siempre produce los resultados correctos -. Invirtiendo pixeles de NSBitmapImageRep
Estoy volver a colocar el 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];