quitar puso poner pantalla negro grises gris escala cómo como color cambio blanco iphone cocoa-touch cgimage

iphone - puso - Convertir imagen a escala de grises



mi iphone cambio de color la pantalla (12)

Estoy intentando convertir una imagen en escala de grises de la siguiente manera:

#define bytesPerPixel 4 #define bitsPerComponent 8 -(unsigned char*) getBytesForImage: (UIImage*)pImage { CGImageRef image = [pImage CGImage]; NSUInteger width = CGImageGetWidth(image); NSUInteger height = CGImageGetHeight(image); NSUInteger bytesPerRow = bytesPerPixel * width; CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); unsigned char *rawData = malloc(height * width * 4); CGContextRef context = CGBitmapContextCreate(rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); CGColorSpaceRelease(colorSpace); CGContextDrawImage(context, CGRectMake(0, 0, width, height), image); CGContextRelease(context); return rawData; } -(UIImage*) processImage: (UIImage*)pImage { DebugLog(@"processing image"); unsigned char *rawData = [self getBytesForImage: pImage]; NSUInteger width = pImage.size.width; NSUInteger height = pImage.size.height; DebugLog(@"width: %d", width); DebugLog(@"height: %d", height); NSUInteger bytesPerRow = bytesPerPixel * width; for (int xCoordinate = 0; xCoordinate < width; xCoordinate++) { for (int yCoordinate = 0; yCoordinate < height; yCoordinate++) { int byteIndex = (bytesPerRow * yCoordinate) + xCoordinate * bytesPerPixel; //Getting original colors float red = ( rawData[byteIndex] / 255.f ); float green = ( rawData[byteIndex + 1] / 255.f ); float blue = ( rawData[byteIndex + 2] / 255.f ); //Processing pixel data float averageColor = (red + green + blue) / 3.0f; red = averageColor; green = averageColor; blue = averageColor; //Assigning new color components rawData[byteIndex] = (unsigned char) red * 255; rawData[byteIndex + 1] = (unsigned char) green * 255; rawData[byteIndex + 2] = (unsigned char) blue * 255; } } NSData* newPixelData = [NSData dataWithBytes: rawData length: height * width * 4]; UIImage* newImage = [UIImage imageWithData: newPixelData]; free(rawData); DebugLog(@"image processed"); return newImage; }

Entonces cuando quiero convertir una imagen solo llamo processImage:

imageToDisplay.image = [self processImage: image];

Pero imageToDisplay no se muestra. ¿Cuál puede ser el problema?

Gracias.


¿Qué ocurre exactamente cuando usas esta función? ¿La función devuelve una imagen no válida o la pantalla no la muestra correctamente?

Este es el método que uso para convertir a escala de grises.

- (UIImage *) convertToGreyscale:(UIImage *)i { int kRed = 1; int kGreen = 2; int kBlue = 4; int colors = kGreen | kBlue | kRed; int m_width = i.size.width; int m_height = i.size.height; uint32_t *rgbImage = (uint32_t *) malloc(m_width * m_height * sizeof(uint32_t)); CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); CGContextRef context = CGBitmapContextCreate(rgbImage, m_width, m_height, 8, m_width * 4, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipLast); CGContextSetInterpolationQuality(context, kCGInterpolationHigh); CGContextSetShouldAntialias(context, NO); CGContextDrawImage(context, CGRectMake(0, 0, m_width, m_height), [i CGImage]); CGContextRelease(context); CGColorSpaceRelease(colorSpace); // now convert to grayscale uint8_t *m_imageData = (uint8_t *) malloc(m_width * m_height); for(int y = 0; y < m_height; y++) { for(int x = 0; x < m_width; x++) { uint32_t rgbPixel=rgbImage[y*m_width+x]; uint32_t sum=0,count=0; if (colors & kRed) {sum += (rgbPixel>>24)&255; count++;} if (colors & kGreen) {sum += (rgbPixel>>16)&255; count++;} if (colors & kBlue) {sum += (rgbPixel>>8)&255; count++;} m_imageData[y*m_width+x]=sum/count; } } free(rgbImage); // convert from a gray scale image back into a UIImage uint8_t *result = (uint8_t *) calloc(m_width * m_height *sizeof(uint32_t), 1); // process the image back to rgb for(int i = 0; i < m_height * m_width; i++) { result[i*4]=0; int val=m_imageData[i]; result[i*4+1]=val; result[i*4+2]=val; result[i*4+3]=val; } // create a UIImage colorSpace = CGColorSpaceCreateDeviceRGB(); context = CGBitmapContextCreate(result, m_width, m_height, 8, m_width * sizeof(uint32_t), colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipLast); CGImageRef image = CGBitmapContextCreateImage(context); CGContextRelease(context); CGColorSpaceRelease(colorSpace); UIImage *resultUIImage = [UIImage imageWithCGImage:image]; CGImageRelease(image); free(m_imageData); // make sure the data will be released by giving it to an autoreleased NSData [NSData dataWithBytesNoCopy:result length:m_width * m_height]; return resultUIImage; }


Aquí hay otra buena solución como método de categoría en UIImage. Se basa en this publicación de blog y sus comentarios. Pero arreglé un problema de memoria aquí:

- (UIImage *)grayScaleImage { // Create image rectangle with current image width/height CGRect imageRect = CGRectMake(0, 0, self.size.width * self.scale, self.size.height * self.scale); // Grayscale color space CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray(); // Create bitmap content with current image size and grayscale colorspace CGContextRef context = CGBitmapContextCreate(nil, self.size.width * self.scale, self.size.height * self.scale, 8, 0, colorSpace, kCGImageAlphaNone); // Draw image into current context, with specified rectangle // using previously defined context (with grayscale colorspace) CGContextDrawImage(context, imageRect, [self CGImage]); // Create bitmap image info from pixel data in current context CGImageRef grayImage = CGBitmapContextCreateImage(context); // release the colorspace and graphics context CGColorSpaceRelease(colorSpace); CGContextRelease(context); // make a new alpha-only graphics context context = CGBitmapContextCreate(nil, self.size.width * self.scale, self.size.height * self.scale, 8, 0, nil, kCGImageAlphaOnly); // draw image into context with no colorspace CGContextDrawImage(context, imageRect, [self CGImage]); // create alpha bitmap mask from current context CGImageRef mask = CGBitmapContextCreateImage(context); // release graphics context CGContextRelease(context); // make UIImage from grayscale image with alpha mask CGImageRef cgImage = CGImageCreateWithMask(grayImage, mask); UIImage *grayScaleImage = [UIImage imageWithCGImage:cgImage scale:self.scale orientation:self.imageOrientation]; // release the CG images CGImageRelease(cgImage); CGImageRelease(grayImage); CGImageRelease(mask); // return the new grayscale image return grayScaleImage; }


Aquí hay un código que usa solo UIKit y el modo de fusión de luminosidad. Un poco de hack, pero funciona bien.

// Transform the image in grayscale. - (UIImage*) grayishImage: (UIImage*) inputImage { // Create a graphic context. UIGraphicsBeginImageContextWithOptions(inputImage.size, YES, 1.0); CGRect imageRect = CGRectMake(0, 0, inputImage.size.width, inputImage.size.height); // Draw the image with the luminosity blend mode. // On top of a white background, this will give a black and white image. [inputImage drawInRect:imageRect blendMode:kCGBlendModeLuminosity alpha:1.0]; // Get the resulting image. UIImage *filteredImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return filteredImage; }

Para mantener la transparencia, tal vez solo pueda establecer el parámetro de modo opaque de UIGraphicsBeginImageContextWithOptions en NO . Necesita ser revisado.


Basado en el código de Cam con la capacidad de lidiar con la báscula para pantallas Retina.

- (UIImage *) toGrayscale { const int RED = 1; const int GREEN = 2; const int BLUE = 3; // Create image rectangle with current image width/height CGRect imageRect = CGRectMake(0, 0, self.size.width * self.scale, self.size.height * self.scale); int width = imageRect.size.width; int height = imageRect.size.height; // the pixels will be painted to this array uint32_t *pixels = (uint32_t *) malloc(width * height * sizeof(uint32_t)); // clear the pixels so any transparency is preserved memset(pixels, 0, width * height * sizeof(uint32_t)); CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); // create a context with RGBA pixels CGContextRef context = CGBitmapContextCreate(pixels, width, height, 8, width * sizeof(uint32_t), colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedLast); // paint the bitmap to our context which will fill in the pixels array CGContextDrawImage(context, CGRectMake(0, 0, width, height), [self CGImage]); for(int y = 0; y < height; y++) { for(int x = 0; x < width; x++) { uint8_t *rgbaPixel = (uint8_t *) &pixels[y * width + x]; // convert to grayscale using recommended method: http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale uint8_t gray = (uint8_t) ((30 * rgbaPixel[RED] + 59 * rgbaPixel[GREEN] + 11 * rgbaPixel[BLUE]) / 100); // set the pixels to gray rgbaPixel[RED] = gray; rgbaPixel[GREEN] = gray; rgbaPixel[BLUE] = gray; } } // create a new CGImageRef from our context with the modified pixels CGImageRef image = CGBitmapContextCreateImage(context); // we''re done with the context, color space, and pixels CGContextRelease(context); CGColorSpaceRelease(colorSpace); free(pixels); // make a new UIImage to return UIImage *resultUIImage = [UIImage imageWithCGImage:image scale:self.scale orientation:UIImageOrientationUp]; // we''re done with image now too CGImageRelease(image); return resultUIImage; }


Enfoque diferente con CIFilter. Conserva el canal alfa y funciona con fondo transparente:

+ (UIImage *)convertImageToGrayScale:(UIImage *)image { CIImage *inputImage = [CIImage imageWithCGImage:image.CGImage]; CIContext *context = [CIContext contextWithOptions:nil]; CIFilter *filter = [CIFilter filterWithName:@"CIColorControls"]; [filter setValue:inputImage forKey:kCIInputImageKey]; [filter setValue:@(0.0) forKey:kCIInputSaturationKey]; CIImage *outputImage = filter.outputImage; CGImageRef cgImageRef = [context createCGImage:outputImage fromRect:outputImage.extent]; UIImage *result = [UIImage imageWithCGImage:cgImageRef]; CGImageRelease(cgImageRef); return result; }


Es mi intento de convertir rápido dibujando directamente en el espacio de color de escala de grises sin cada enumeración de píxeles. Funciona 10 veces más rápido que CIImageFilter soluciones CIImageFilter .

@implementation UIImage (Grayscale) static UIImage *grayscaleImageFromCIImage(CIImage *image, CGFloat scale) { CIImage *blackAndWhite = [CIFilter filterWithName:@"CIColorControls" keysAndValues:kCIInputImageKey, image, kCIInputBrightnessKey, @0.0, kCIInputContrastKey, @1.1, kCIInputSaturationKey, @0.0, nil].outputImage; CIImage *output = [CIFilter filterWithName:@"CIExposureAdjust" keysAndValues:kCIInputImageKey, blackAndWhite, kCIInputEVKey, @0.7, nil].outputImage; CGImageRef ref = [[CIContext contextWithOptions:nil] createCGImage:output fromRect:output.extent]; UIImage *result = [UIImage imageWithCGImage:ref scale:scale orientation:UIImageOrientationUp]; CGImageRelease(ref); return result; } static UIImage *grayscaleImageFromCGImage(CGImageRef imageRef, CGFloat scale) { NSInteger width = CGImageGetWidth(imageRef) * scale; NSInteger height = CGImageGetHeight(imageRef) * scale; NSMutableData *pixels = [NSMutableData dataWithLength:width*height]; CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray(); CGContextRef context = CGBitmapContextCreate(pixels.mutableBytes, width, height, 8, width, colorSpace, 0); CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef); CGImageRef ref = CGBitmapContextCreateImage(context); UIImage *result = [UIImage imageWithCGImage:ref scale:scale orientation:UIImageOrientationUp]; CGContextRelease(context); CGColorSpaceRelease(colorSpace); CGImageRelease(ref); return result; } - (UIImage *)grayscaleImage { if (self.CIImage) { return grayscaleImageFromCIImage(self.CIImage, self.scale); } else if (self.CGImage) { return grayscaleImageFromCGImage(self.CGImage, self.scale); } return nil; } @end


Me gustó la respuesta de Mathieu Godart, pero no pareció funcionar correctamente para la retina o las imágenes alfa. Aquí hay una versión actualizada que parece funcionar para los dos para mí:

- (UIImage*)convertToGrayscale { UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale); CGRect imageRect = CGRectMake(0.0f, 0.0f, self.size.width, self.size.height); CGContextRef ctx = UIGraphicsGetCurrentContext(); // Draw a white background CGContextSetRGBFillColor(ctx, 1.0f, 1.0f, 1.0f, 1.0f); CGContextFillRect(ctx, imageRect); // Draw the luminosity on top of the white background to get grayscale [self drawInRect:imageRect blendMode:kCGBlendModeLuminosity alpha:1.0f]; // Apply the source image''s alpha [self drawInRect:imageRect blendMode:kCGBlendModeDestinationIn alpha:1.0f]; UIImage* grayscaleImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return grayscaleImage; }


Necesitaba una versión que conservara el canal alfa, así que modifiqué el código publicado por Dutchie432:

@implementation UIImage (grayscale) typedef enum { ALPHA = 0, BLUE = 1, GREEN = 2, RED = 3 } PIXELS; - (UIImage *)convertToGrayscale { CGSize size = [self size]; int width = size.width; int height = size.height; // the pixels will be painted to this array uint32_t *pixels = (uint32_t *) malloc(width * height * sizeof(uint32_t)); // clear the pixels so any transparency is preserved memset(pixels, 0, width * height * sizeof(uint32_t)); CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); // create a context with RGBA pixels CGContextRef context = CGBitmapContextCreate(pixels, width, height, 8, width * sizeof(uint32_t), colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedLast); // paint the bitmap to our context which will fill in the pixels array CGContextDrawImage(context, CGRectMake(0, 0, width, height), [self CGImage]); for(int y = 0; y < height; y++) { for(int x = 0; x < width; x++) { uint8_t *rgbaPixel = (uint8_t *) &pixels[y * width + x]; // convert to grayscale using recommended method: http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale uint32_t gray = 0.3 * rgbaPixel[RED] + 0.59 * rgbaPixel[GREEN] + 0.11 * rgbaPixel[BLUE]; // set the pixels to gray rgbaPixel[RED] = gray; rgbaPixel[GREEN] = gray; rgbaPixel[BLUE] = gray; } } // create a new CGImageRef from our context with the modified pixels CGImageRef image = CGBitmapContextCreateImage(context); // we''re done with the context, color space, and pixels CGContextRelease(context); CGColorSpaceRelease(colorSpace); free(pixels); // make a new UIImage to return UIImage *resultUIImage = [UIImage imageWithCGImage:image]; // we''re done with image now too CGImageRelease(image); return resultUIImage; } @end


Tengo otra respuesta. Este es extremadamente eficiente y maneja los gráficos retina, así como la transparencia. Se amplía con el enfoque de Sargis Gevorgyan:

+ (UIImage*) grayScaleFromImage:(UIImage*)image opaque:(BOOL)opaque { // NSTimeInterval start = [NSDate timeIntervalSinceReferenceDate]; CGSize size = image.size; CGRect bounds = CGRectMake(0, 0, size.width, size.height); // Create bitmap content with current image size and grayscale colorspace CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray(); size_t bitsPerComponent = 8; size_t bytesPerPixel = opaque ? 1 : 2; size_t bytesPerRow = bytesPerPixel * size.width * image.scale; CGContextRef context = CGBitmapContextCreate(nil, size.width, size.height, bitsPerComponent, bytesPerRow, colorSpace, opaque ? kCGImageAlphaNone : kCGImageAlphaPremultipliedLast); // create image from bitmap CGContextDrawImage(context, bounds, image.CGImage); CGImageRef cgImage = CGBitmapContextCreateImage(context); UIImage* result = [[UIImage alloc] initWithCGImage:cgImage scale:image.scale orientation:UIImageOrientationUp]; CGImageRelease(cgImage); CGContextRelease(context); // performance results on iPhone 6S+ in Release mode. // Results are in photo pixels, not device pixels: // ~ 5ms for 500px x 600px // ~ 15ms for 2200px x 600px // NSLog(@"generating %d x %d @ %dx grayscale took %f seconds", (int)size.width, (int)size.height, (int)image.scale, [NSDate timeIntervalSinceReferenceDate] - start); return result; }

En su lugar, usar modos de fusión es elegante, pero copiar a un mapa de bits en escala de grises es más eficaz porque solo utiliza uno o dos canales de color en lugar de cuatro. El bool de opacidad está destinado a incluir el indicador opaco de tu UIView para que puedas optar por no usar un canal alfa si sabes que no necesitarás uno.

No he probado las soluciones basadas en Core Image en este hilo de respuestas, pero sería muy prudente sobre el uso de Core Image si el rendimiento es importante.


Una implementación rápida y eficiente de Swift 3 para iOS 9/10. Siento que esto es eficiente ya que he probado todos los métodos de filtrado de imágenes que pude encontrar para procesar cientos de imágenes a la vez (al descargar usando la opción ImageFilter de AlamofireImage). Me decidí por este método como FAR mejor que cualquier otro que probé (para mi caso de uso) en términos de memoria y velocidad.

func convertToGrayscale() -> UIImage? { UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale) let imageRect = CGRect(x: 0.0, y: 0.0, width: self.size.width, height: self.size.height) let context = UIGraphicsGetCurrentContext() // Draw a white background context!.setFillColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0) context!.fill(imageRect) // optional: increase contrast with colorDodge before applying luminosity // (my images were too dark when using just luminosity - you may not need this) self.draw(in: imageRect, blendMode: CGBlendMode.colorDodge, alpha: 0.7) // Draw the luminosity on top of the white background to get grayscale of original image self.draw(in: imageRect, blendMode: CGBlendMode.luminosity, alpha: 0.90) // optional: re-apply alpha if your image has transparency - based on user1978534''s answer (I haven''t tested this as I didn''t have transparency - I just know this would be the the syntax) // self.draw(in: imageRect, blendMode: CGBlendMode.destinationIn, alpha: 1.0) let grayscaleImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return grayscaleImage }


Re el uso de colorDodge: Inicialmente tuve problemas para que mis imágenes fueran lo suficientemente livianas como para coincidir con la coloración en escala de grises producida al usar CIFilter ("CIPhotoEffectTonal"); mis resultados resultaron demasiado oscuros. Pude obtener una coincidencia decente al aplicar CGBlendMode.colorDodge @ ~ 0.7 alpha, lo que parece aumentar el contraste general.

También podrían funcionar otros efectos de mezcla de colores, pero creo que le gustaría aplicar antes de luminocity, que es el efecto de filtrado en escala de grises. Encontré esta página muy útil para hacer referencia a los diferentes BlendModes .



Re ganancias de eficiencia que encontré: necesito procesar cientos de imágenes en miniatura a medida que se cargan desde un servidor (usando AlamofireImage para carga asíncrona, almacenamiento en caché y aplicación de un filtro). Empecé a experimentar bloqueos cuando el tamaño total de mis imágenes excedía el tamaño de caché, por lo que experimenté con otros métodos.

El enfoque CIFilter basado en la CPU CoreImage fue el primero que probé, y no era lo suficientemente eficiente en cuanto a la memoria para la cantidad de imágenes que estoy manejando.

También traté de aplicar un CIFilter a través de la GPU usando EAGLContext(api: .openGLES3) , que en realidad EAGLContext(api: .openGLES3) aún más memoria: en realidad recibí advertencias de memoria para uso de más de 450 mb mientras cargaba más de 200 imágenes.

Intenté el procesamiento de mapa de bits (es decir, CGContext(data: nil, width: width, height: height, bitsPerComponent: 8, bytesPerRow: 0, space: colorSpace, bitmapInfo: CGImageAlphaInfo.none.rawValue) ... que funcionó bien, excepto que no pude Obtenga una resolución lo suficientemente alta para un dispositivo de retina moderno. Las imágenes eran muy granuladas incluso cuando agregué context.scaleBy(x: scaleFactor, y: scaleFactor) .

Así que de todo lo que probé, este método (UIGraphics Context Draw) es VASTLY más eficiente en cuanto a velocidad y memoria cuando se aplica como filtro a AlamofireImage. Al igual que en el caso, al ver menos de 70 mbs ram al procesar mis más de 200 imágenes y básicamente cargarlas al instante, en lugar de durante aproximadamente 35 segundos, se realizaron con los métodos openEAGL. Sé que estos no son puntos de referencia muy científicos. Lo instrumentaré si alguien es muy curioso sin embargo :)


Y, por último, si necesita pasar este u otro filtro de escala de grises en AlamofireImage, esta es la forma de hacerlo: (tenga en cuenta que debe importar AlamofireImage a su clase para usar ImageFilter)

public struct GrayScaleFilter: ImageFilter { public init() { } public var filter: (UIImage) -> UIImage { return { image in return image.convertToGrayscale() ?? image } } }

Para usarlo, crea el filtro de esta manera y pasa a af_setImage de la siguiente manera:

let filter = GrayScaleFilter() imageView.af_setImage(withURL: url, filter: filter)


Una extensión rápida a UIImage , preservando alfa:

extension UIImage { private func convertToGrayScaleNoAlpha() -> CGImageRef { let colorSpace = CGColorSpaceCreateDeviceGray(); let bitmapInfo = CGBitmapInfo(CGImageAlphaInfo.None.rawValue) let context = CGBitmapContextCreate(nil, UInt(size.width), UInt(size.height), 8, 0, colorSpace, bitmapInfo) CGContextDrawImage(context, CGRectMake(0, 0, size.width, size.height), self.CGImage) return CGBitmapContextCreateImage(context) } /** Return a new image in shades of gray + alpha */ func convertToGrayScale() -> UIImage { let bitmapInfo = CGBitmapInfo(CGImageAlphaInfo.Only.rawValue) let context = CGBitmapContextCreate(nil, UInt(size.width), UInt(size.height), 8, 0, nil, bitmapInfo) CGContextDrawImage(context, CGRectMake(0, 0, size.width, size.height), self.CGImage); let mask = CGBitmapContextCreateImage(context) return UIImage(CGImage: CGImageCreateWithMask(convertToGrayScaleNoAlpha(), mask), scale: scale, orientation:imageOrientation)! } }


@interface UIImageView (Settings) - (void)convertImageToGrayScale; @end @implementation UIImageView (Settings) - (void)convertImageToGrayScale { // Create image rectangle with current image width/height CGRect imageRect = CGRectMake(0, 0, self.image.size.width, self.image.size.height); // Grayscale color space CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray(); // Create bitmap content with current image size and grayscale colorspace CGContextRef context = CGBitmapContextCreate(nil, self.image.size.width, self.image.size.height, 8, 0, colorSpace, kCGImageAlphaNone); // Draw image into current context, with specified rectangle // using previously defined context (with grayscale colorspace) CGContextDrawImage(context, imageRect, [self.image CGImage]); // Create bitmap image info from pixel data in current context CGImageRef imageRef = CGBitmapContextCreateImage(context); // Create a new UIImage object UIImage *newImage = [UIImage imageWithCGImage:imageRef]; // Release colorspace, context and bitmap information CGColorSpaceRelease(colorSpace); CGContextRelease(context); CFRelease(imageRef); // Return the new grayscale image self.image = newImage; } @end