Любая идея, почему этот код маскировки изображений не работает?
У меня есть этот код для маскировки изображения. В основном, я работаю только с изображениями PNG. Итак, у меня есть PNG-изображение 300x400 с 24-битным цветом (PNG-24). Я не уверен, что у него также есть альфа-канал. Но в этом нет прозрачности.
Тогда есть маска изображения, которая является PNG-8 бит без альфа-канала. Это только черный, полутоновый и белый.
Я создаю оба изображения как UIImage. Оба дисплея отображаются правильно, когда помещаются в UIImageView.
Затем я создаю из них UIImage, который содержит результаты операции маскировки, с помощью этого кода:
+ (UIImage*)maskImage:(UIImage*)image withMask:(UIImage*)maskImage {
CGImageRef maskRef = maskImage.CGImage;
CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef),
CGImageGetHeight(maskRef),
CGImageGetBitsPerComponent(maskRef),
CGImageGetBitsPerPixel(maskRef),
CGImageGetBytesPerRow(maskRef),
CGImageGetDataProvider(maskRef), NULL, false);
CGImageRef masked = CGImageCreateWithMask([image CGImage], mask);
return [UIImage imageWithCGImage:masked];
}
вот что я делаю с этим:
UIImage *image = [UIImage imageNamed:@"coloredImagePNG24.png"];
UIImage *maskImage = [UIImage imageNamed:@"theMaskPNG8_Grayscale_NoAlpha.png"];
UIImage *maskedImage = [MyGraphicUtils maskImage:image withMask:maskImage];
UIImageView *testImageView = [[UIImageView alloc] initWithImage:maskedImage];
testImageView.backgroundColor = [UIColor clearColor];
testImageView.opaque = NO;
В конце концов, colorImagePNG24.png остается полностью неповрежденным. Никакой маскировки не происходит. Но теперь это странно: если я поверну это, то используйте это изображение как маску, а маску, как цветное изображение в маску, тогда я получаю что-то очень уродливое в оттенках серого (но в масках;)).
Любая идея, что не так с моим кодом?
UPDATE: я просто искал Google для другого b/w png, чтобы использовать его в качестве маски. А потом это сработало! Но тот, который я сделал сам, не работает. Поэтому я предполагаю, что код имеет большие проблемы декодирования изображений. Я должен "нормализовать" изображения в определенном формате, чтобы он работал.
Ответы
Ответ 1
Этот код может помочь вам
- (UIImage*) maskImage:(UIImage *)image withMask:(UIImage *)maskImage {
CGImageRef maskRef = maskImage.CGImage;
CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef),
CGImageGetHeight(maskRef),
CGImageGetBitsPerComponent(maskRef),
CGImageGetBitsPerPixel(maskRef),
CGImageGetBytesPerRow(maskRef),
CGImageGetDataProvider(maskRef), NULL, false);
CGImageRef masked = CGImageCreateWithMask([image CGImage], mask);
return [UIImage imageWithCGImage:masked];
}
см. эту демонстрацию
Ответ 2
Как вы выяснили, как сохранить файл может иметь значение, потому что Core Graphics очень специфична в отношении формата бит, который он использует для маскировки.
Ive обнаружил, что лучший и самый надежный способ создания маски изображения из произвольного изображения заключается в следующем:
- Создайте графический контекст растровой графики, который находится в приемлемом формате для масок изображений (для этого вы не можете использовать UIGraphicsBeginImageContext())
- Нарисуйте изображение в этом графическом контексте с растровой графикой.
- Создайте маску изображения из бит графического контекста графической подписи.
Попробуйте эту функцию:
CGImageRef createMaskWithImage(CGImageRef image)
{
int maskWidth = CGImageGetWidth(image);
int maskHeight = CGImageGetHeight(image);
// round bytesPerRow to the nearest 16 bytes, for performance sake
int bytesPerRow = (maskWidth + 15) & 0xfffffff0;
int bufferSize = bytesPerRow * maskHeight;
// allocate memory for the bits
CFMutableDataRef dataBuffer = CFDataCreateMutable(kCFAllocatorDefault, 0);
CFDataSetLength(dataBuffer, bufferSize);
// the data will be 8 bits per pixel, no alpha
CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceGray();
CGContextRef ctx = CGBitmapContextCreate(CFDataGetMutableBytePtr(dataBuffer),
maskWidth, maskHeight,
8, bytesPerRow, colourSpace, kCGImageAlphaNone);
// drawing into this context will draw into the dataBuffer.
CGContextDrawImage(ctx, CGRectMake(0, 0, maskWidth, maskHeight), image);
CGContextRelease(ctx);
// now make a mask from the data.
CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData(dataBuffer);
CGImageRef mask = CGImageMaskCreate(maskWidth, maskHeight, 8, 8, bytesPerRow,
dataProvider, NULL, FALSE);
CGDataProviderRelease(dataProvider);
CGColorSpaceRelease(colourSpace);
CFRelease(dataBuffer);
return mask;
}
Ответ 3
CGImageMaskCreate
не выполняет то, что вы ожидаете. В частности:
Для масок изображений, которые являются 2, 4 или 8 бит на компонент, каждый компонент отображается в диапазоне от 0 до 1 путем масштабирования с использованием этой формулы:
1/(2 ^ бит на компонент - 1)
Например, 4-разрядная маска имеет значения от 0 до 15. Эти значения масштабируются на 1/15, так что каждый компонент находится в диапазоне от 0 до 1. Значения компонентов, которые изменяются до 0 или 1, ведут себя одинаково поскольку они ведут себя для 1-битных масок изображения. Значения, которые масштабируются между 0 и 1, действуют как обратная альфа. То есть цвет заливки окрашен, как если бы он имел альфа-значение (1 - MaskSampleValue). Например, если значение образца 8-разрядной маски масштабируется до 0,8, текущий цвет заливки окрашивается, как если бы он имел значение альфа 0,2, то есть (1-0,8).
Я предполагаю, что функция переинтерпретирует ваши данные RGB в этом другом формате, что искажает значения цвета. Вы пытались напрямую использовать маску CGImage?
Быстрое редактирование: что я подразумеваю под "напрямую", это просто написать
+ (UIImage*)maskImage:(UIImage*)image withMask:(UIImage*)maskImage
{
CGImageRef masked = CGImageCreateWithMask([image CGImage], [maskImage CGImage]);
return [UIImage imageWithCGImage:masked];
}
Ответ 4
Для меня работали следующие строки кода
+(UIImage*)maskImageExt:(UIImage *)image withMask:(UIImage *)maskImage {
CGImageRef maskRef = maskImage.CGImage;
CGImageRef imageRef = image.CGImage;
CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef),
CGImageGetHeight(maskRef),
CGImageGetBitsPerComponent(maskRef),
CGImageGetBitsPerPixel(maskRef),
CGImageGetBytesPerRow(maskRef),
CGImageGetDataProvider(maskRef), NULL, true);
CGImageRef maskImageRef = CGImageCreateWithMask([image CGImage], mask);
CGContextRef context = CGBitmapContextCreate(nil,
CGImageGetWidth(imageRef),
CGImageGetHeight(imageRef),
CGImageGetBitsPerComponent(imageRef),
CGImageGetBytesPerRow(imageRef),
CGImageGetColorSpace(imageRef),
CGImageGetBitmapInfo(imageRef));
CGRect imageRect = CGRectMake(0, 0, CGImageGetWidth(imageRef), CGImageGetHeight(imageRef));
CGContextDrawImage(context, imageRect, maskImageRef);
CGImageRef maskedImageRef = CGBitmapContextCreateImage(context);
UIImage *maskedImage = [UIImage imageWithCGImage:maskedImageRef];
CGImageRelease(mask);
CGContextRelease(context);
CGImageRelease(maskedImageRef);
return maskedImage;
}
Ответ 5
Посмотрите, работает ли это лучше:
+ (UIImage*)maskImage:(UIImage*)image withMask:(UIImage*)maskImage {
UIGraphicsBeginImageContext(image.size);
CGImageRef maskRef = maskImage.CGImage;
CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef), CGImageGetHeight(maskRef), CGImageGetBitsPerComponent(maskRef), CGImageGetBitsPerPixel(maskRef), CGImageGetBytesPerRow(maskRef), CGImageGetDataProvider(maskRef), NULL, false);
CGImageRef masked = CGImageCreateWithMask(image.CGImage, mask);
UIImage* result = [UIImage imageWithData:UIImagePNGRepresentation(UIGraphicsGetImageFromCurrentImageContext())];
UIGraphicsEndImageContext();
CGImageRelease(mask);
CGImageRelease(masked);
return result;
}
Ответ 6
Дэйв, я слышал о изображениях PNG с альфа-каналом, которые могут повлиять на такой код.
Я просто искал PNG Alpha Channel и придумал эту ссылку: текст ссылки
Итак, убедитесь, что PNG, который вы используете, имеет правильно настроенный альфа-канал
Ответ 7
Вы НЕ МОЖЕТЕ создать изображение любого типа с основной графикой, у которой нет альфа-канала.