I'm trying to create a SKEffectNode that will turn transparent any green pixel over a black background. For testing purposes while I figure this stuff out, I want to make sure that the following code will not turn anything transparent within the subtree of the SKEffectNode. The following code actually prevents the child from being drawn and it spits up the following error:

CIColorCube inputCubeData is not of the expected length.

That's the method that creates the SKEffectNode

- (SKEffectNode *) newVeil
{
    SKEffectNode *node = [[SKEffectNode alloc] init];

    node.shouldEnableEffects = YES;
    node.filter = [self createFilter];

    SKSpriteNode *darkness = [SKSpriteNode spriteNodeWithColor:[UIColor blackColor] size:self.view.frame.size];
    node.position = self.view.center;
    [node addChild:darkness];

    return node;
}

That's how I setup the filter (most, or dare I say all of this code is in Apple's dev documents).

- (CIFilter *) createFilter
{
    // Allocate memory
    const unsigned int size = 64;
    float *cubeData = (float *)malloc (size * size * size * sizeof (float) * 4);
    float *c = cubeData;
    rgb rgbInput;
    hsv hsvOutput;

    // Populate cube with a simple gradient going from 0 to 1
    for (int z = 0; z < size; z++){
        rgbInput.b = ((double)z)/(size-1); // Blue value
        for (int y = 0; y < size; y++){
            rgbInput.g = ((double)y)/(size-1); // Green value
            for (int x = 0; x < size; x ++){
                rgbInput.r = ((double)x)/(size-1); // Red value
                // Convert RGB to HSV
                // You can find publicly available rgbToHSV functions on the Internet
                hsvOutput = rgb2hsv(rgbInput);
                // Use the hue value to determine which to make transparent
                // The minimum and maximum hue angle depends on
                // the color you want to remove
                float alpha = (hsvOutput.h > 120 && hsvOutput.h < 100) ? 0.0f: 1.0f;
                // Calculate premultiplied alpha values for the cube
                c[0] = rgbInput.b * alpha;
                c[1] = rgbInput.g * alpha;
                c[2] = rgbInput.r * alpha;
                c[3] = alpha;
                c += 4; // advance our pointer into memory for the next color value
            }
        }
    }
    // Create memory with the cube data
    NSData *data = [NSData dataWithBytesNoCopy:cubeData
                                        length:size
                                  freeWhenDone:YES];

    CIFilter *colorCube = [CIFilter filterWithName:@"CIColorCube"];
    [colorCube setValue:@(size) forKey:@"inputCubeDimension"];
    // Set data for cube
    [colorCube setValue:data forKey:@"inputCubeData"];

    return colorCube;
}

I just can't spot the problem. Not a whole lot of experience with CoreImage. Anyone?

Update 1

I tried exporting the whole CIFilter into it's own class.

//  PMColorCube.h

#import <CoreImage/CoreImage.h>

@interface PMColorCube : CIFilter{
    CIImage *inputImage;
}
@property (retain, nonatomic) CIImage *inputImage;
@end



//  PMColorCube.m

#import "PMColorCube.h"

typedef struct {
    double r;       // percent
    double g;       // percent
    double b;       // percent
} rgb;

typedef struct {
    double h;       // angle in degrees
    double s;       // percent
    double v;       // percent
} hsv;

static hsv      rgb2hsv(rgb in);

@implementation PMColorCube
@synthesize inputImage;

hsv rgb2hsv(rgb in)
{
    hsv         out;
    double      min, max, delta;

    min = in.r < in.g ? in.r : in.g;
    min = min  < in.b ? min  : in.b;

    max = in.r > in.g ? in.r : in.g;
    max = max  > in.b ? max  : in.b;

    out.v = max;                                // v
    delta = max - min;
    if( max > 0.0 ) {
        out.s = (delta / max);                  // s
    } else {
        // r = g = b = 0                        // s = 0, v is undefined
        out.s = 0.0;
        out.h = NAN;                            // its now undefined
        return out;
    }
    if( in.r >= max )                           // > is bogus, just keeps compilor happy
        out.h = ( in.g - in.b ) / delta;        // between yellow & magenta
    else
        if( in.g >= max )
            out.h = 2.0 + ( in.b - in.r ) / delta;  // between cyan & yellow
        else
            out.h = 4.0 + ( in.r - in.g ) / delta;  // between magenta & cyan

    out.h *= 60.0;                              // degrees

    if( out.h < 0.0 )
        out.h += 360.0;

    return out;
}

- (CIImage *) outputImage
{
    const unsigned int size = 64;
    float *cubeData = (float *)malloc (size * size * size * sizeof (float) * 4);
    float *c = cubeData;
    rgb rgbInput;
    hsv hsvOutput;

    // Populate cube with a simple gradient going from 0 to 1
    for (int z = 0; z < size; z++){
        rgbInput.b = ((double)z)/(size-1); // Blue value
        for (int y = 0; y < size; y++){
            rgbInput.g = ((double)y)/(size-1); // Green value
            for (int x = 0; x < size; x ++){
                rgbInput.r = ((double)x)/(size-1); // Red value
                // Convert RGB to HSV
                // You can find publicly available rgbToHSV functions on the Internet
                hsvOutput = rgb2hsv(rgbInput);
                // Use the hue value to determine which to make transparent
                // The minimum and maximum hue angle depends on
                // the color you want to remove
                float alpha = (hsvOutput.h > 120 && hsvOutput.h < 100) ? 0.0f: 1.0f;
                // Calculate premultiplied alpha values for the cube
                c[0] = rgbInput.b * alpha;
                c[1] = rgbInput.g * alpha;
                c[2] = rgbInput.r * alpha;
                c[3] = alpha;
                c += 4; // advance our pointer into memory for the next color value
            }
        }
    }
    // Create memory with the cube data
    NSData *data = [NSData dataWithBytesNoCopy:cubeData
                                        length:size
                                  freeWhenDone:YES];

    CIFilter *colorCube = [CIFilter filterWithName:@"CIColorCube"];
    [colorCube setValue:@(size) forKey:@"inputCubeDimension"];
    // Set data for cube
    [colorCube setValue:data forKey:@"inputCubeData"];

    [colorCube setValue:self.inputImage forKey:kCIInputImageKey];
    CIImage *result = [colorCube valueForKey:kCIOutputImageKey];

    return result;
}
@end

I still have the same error during run time

有帮助吗?

解决方案

Embarrassing as it may sound. The size that I pass in the class method when creating the NSData doesn't correspond to the real size. Fixed it like so:

    // Create memory with the cube data
    NSData *data = [NSData dataWithBytesNoCopy:cubeData
                                        length:size * size * size * sizeof (float) * 4
                                  freeWhenDone:YES];
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top