кварцевые маски в iOS все еще вызывают сбои?

Согласно этому вопросу от 2008 года, использование кварцевых масок может вызывать сбои! Так ли это до сих пор?

По сути, я хочу нарисовать кубики разных цветов на фиксированном фоне, используя один png для каждой формы кубика (их много), и каким-то образом добавить цвета в код.

РЕДАКТИРОВАТЬ: чтобы уточнить, например, я хочу использовать один файл png, чтобы сделать все следующее:

Красный кубикСиний кубик Белый кубик

По сути, я хочу умножить красный, зеленый и синий компоненты моего изображения на три независимые константы, оставив альфа неизменным.


person William Jockusch    schedule 26.04.2011    source источник
comment
Награда предназначена для всех, кто может объяснить, как я могу достичь того, чего хочу (см. Выше). Меня не волнует, связано ли это с масками или нет, но он не может быть уязвим для сбоев.   -  person William Jockusch    schedule 01.05.2011


Ответы (2)


Вот снимок. Проверено, утечек нет. Никаких сбоев.

.h

#import <UIKit/UIKit.h>

@interface ImageModViewController : UIViewController {

}
@property (nonatomic, retain) IBOutlet UIButton *test_button;
@property (nonatomic, retain) IBOutlet UIImageView *source_image;
@property (nonatomic, retain) IBOutlet UIImageView *destination_image;
@property (nonatomic, assign) float kr;
@property (nonatomic, assign) float kg;
@property (nonatomic, assign) float kb;
@property (nonatomic, assign) float ka;


-(IBAction)touched_test_button:(id)sender;

-(UIImage *) MultiplyImagePixelsByRGBA:(UIImage *)source  kr:(float)red_k  kg:(float)green_k  kb:(float)blue_k  ka:(float)alpha_k;


@end

.m

#define BITS_PER_WORD       32
#define BITS_PER_CHANNEL    8
#define COLOR_CHANNELS      4
#define BYTES_PER_PIXEL     BITS_PER_WORD / BITS_PER_CHANNEL


#import "ImageModViewController.h"

@implementation ImageModViewController

@synthesize test_button;
@synthesize source_image;
@synthesize destination_image;
@synthesize kr;
@synthesize kg;
@synthesize kb;
@synthesize ka;


-(IBAction)touched_test_button:(id)sender
{

    // Setup coefficients

    kr = 1.0;
    kg = 0.0;
    kb = 0.0;
    ka = 1.0;

    // Set UIImageView image to the result of multiplying the pixels by the coefficients

    destination_image.image = [self MultiplyImagePixelsByRGBA:source_image.image kr:kr kg:kg kb:kb ka:ka];

}

-(UIImage *) MultiplyImagePixelsByRGBA:(UIImage *)source  kr:(float)red_k  kg:(float)green_k  kb:(float)blue_k  ka:(float)alpha_k
{

    // Get image information
    CGImageRef bitmap     = [source CGImage];
    int width             = source.size.width;
    int height            = source.size.height;
    int total_pixels      = width * height;

    // Allocate a buffer
    unsigned char *buffer = malloc(total_pixels * COLOR_CHANNELS);

    // Copy image data to buffer
    CGColorSpaceRef cs   = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(buffer, width, height, BITS_PER_CHANNEL, width * BYTES_PER_PIXEL, cs, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrderDefault);
    CGColorSpaceRelease(cs);
    CGContextDrawImage(context, CGRectMake(0, 0, width, height), bitmap);
    CGContextRelease(context);

    // Bounds limit coefficients
    kr = ((((kr < 0.0) ? 0.0 : kr) > 1.0) ? 1.0 : kr);
    kg = ((((kg < 0.0) ? 0.0 : kg) > 1.0) ? 1.0 : kg);
    kb = ((((kb < 0.0) ? 0.0 : kb) > 1.0) ? 1.0 : kb);
    ka = ((((ka < 0.0) ? 0.0 : ka) > 1.0) ? 1.0 : ka);

    // Process the image in the buffer

    int offset = 0;     // Used to index into the buffer

    for (int i = 0 ; i < total_pixels; i++)
    {
        buffer[offset] = (char)(buffer[offset] * red_k);   offset++;

        buffer[offset] = (char)(buffer[offset] * green_k); offset++;

        buffer[offset] = (char)(buffer[offset] * blue_k);  offset++;

        buffer[offset] = (char)(buffer[offset] * alpha_k); offset++;
    }

    // Put the image back into a UIImage
    context = CGBitmapContextCreate(buffer, width, height, BITS_PER_CHANNEL, width * BYTES_PER_PIXEL, cs, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrderDefault);
    bitmap  = CGBitmapContextCreateImage(context);
    UIImage *output = [UIImage imageWithCGImage:bitmap];

    CGContextRelease(context);
    free(buffer);

    return output;

}


- (void)dealloc
{
    [super dealloc];
}

- (void)didReceiveMemoryWarning
{
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];

    // Release any cached data, images, etc that aren't in use.
}

#pragma mark - View lifecycle

/*
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
    [super viewDidLoad];
}
*/

- (void)viewDidUnload
{
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    // Return YES for supported orientations
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

@end

Я устанавливаю xib с двумя UIImageViews и одним UIButton. Верхний UIImageView был предварительно загружен с изображением с помощью Interface Builder. Коснитесь текстовой кнопки, и изображение будет обработано и настроено на второй UIImageView.

Кстати, у меня были небольшие проблемы с вашими иконками, скопированными прямо с вашего поста. По какой-то причине прозрачность работала не очень хорошо. Я использовал собственные свежие тестовые изображения PNG, созданные в Photoshop с прозрачностью и без нее, и все работало, как рекламируется.

То, что вы делаете внутри цикла, конечно же, должно быть изменено в соответствии с вашими потребностями.

Следите за порядком следования байтов, это действительно может все испортить!

person martin's    schedule 04.05.2011

В последнее время я довольно часто использовал маски в приложении для iPhone, без сбоев. Код в этой ссылке, похоже, даже не использует маски, а просто отсекает; единственное упоминание о масках было как о чем-то еще, что он пробовал. Скорее всего, он вызвал это из фонового потока, UIGraphicsBeginImageContext не является потокобезопасным.

Не зная точно, какой эффект вы пытаетесь получить, трудно дать совет, как это сделать. Маска, безусловно, может работать либо сама по себе (чтобы получить своего рода эффект шелкографии), либо для обрезки наложенного цвета, нарисованного на более реалистичном изображении. Я бы, вероятно, использовал маску или контур для установки отсечения, затем нарисовал изображение кристалла (используя kCBGlendModeNormal или kCBGlendModeCopy), а затем закрасил бы его соответствующим сплошным цветом, используя kCGBlendModeColor.

person Anomie    schedule 01.05.2011