Недавно мне нужно было решить эту задачу для одного из проектов под iPhone. Естественное, на помощь я позвал Google, который показал мне ссылки сразу на несколько вариантов решения. Однако не все они справились с поставленной задачей должным образом. Все реализации, испробованные мною в начале, «забывали» про альфа-канал. Они преобразовывали его в черный цвет, что было для меня неприемлемо. Альфа-канал должен был сохраняться. Поэтому я стал просматривать варианты более внимательно. Нужную мне реализацию я нашел акурат под ранее не подошедшей. На ней я и остановился. А ниже привожу её исходный код на Objective-C. Для себя, чтобы не искать потом снова, а может и еще кому-нибудь пригодится.
typedef enum {
ALPHA = 0,
BLUE = 1,
GREEN = 2,
RED = 3
} PIXELS;
//конвертирует картинку в "черно-белую" с сохранением альфа-канала
+ (UIImage *)convertToGrayscale:(UIImage*)img {
CGSize size = [img size];
int width = size.width;
int height = size.height;
// пиксели будут рисоваться в этот массив
uint32_t *pixels = (uint32_t *) malloc(width * height * sizeof(uint32_t));
// очищаем пиксели с сохранением прозрачности
memset(pixels, 0, width * height * sizeof(uint32_t));
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
// создаем контекст с RGBA-пикселями
CGContextRef context = CGBitmapContextCreate(pixels, width, height, 8, width * sizeof(uint32_t), colorSpace,
kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedLast);
// отображаем картинку на наш контекст
CGContextDrawImage(context, CGRectMake(0, 0, width, height), [img CGImage]);
for(int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
uint8_t *rgbaPixel = (uint8_t *) &pixels[y * width + x];
// преобразуем в черно-белый формат, используя следующий метод: 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];
// устанавливаем пиксели в серый
rgbaPixel[RED] = gray;
rgbaPixel[GREEN] = gray;
rgbaPixel[BLUE] = gray;
}
}
// создаем CGImageRef из нашего контекста с модифицированными пикселями
CGImageRef image = CGBitmapContextCreateImage(context);
// завершаем работу с context, color space, и pixels
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
free(pixels);
// создаем новый UIImage для возвращения
UIImage *resultUIImage = [UIImage imageWithCGImage:image];
// завершаем работу с image
CGImageRelease(image);
return resultUIImage;
}
В результативности приведенного Objective-C кода я убедился сам. Результат отличный — рекомендую :)
Полезная статья? Их будет больше, если вы поддержите меня!