CILinearGradient drawing backwards in 10.5

  • As of Leopard, when I attempt to draw a linear gradient
    (CILinearGradient) via any kind of context--an NSImage, an NSView
    drawing itself (flipped or not), etc--the gradient start and end
    colours are backwards. That is, if I start the gradient at black and
    end it at white, it will appear on-screen as though I started at
    white and ended at black. In Tiger, I did not have this problem.

    I draw the gradient inside of an NSBezierPath category:

    - (void)fillUsingLinearGradientWithStartColour:(NSColor *)startColour
    startVector:(NSPoint)startVector endColour:(NSColor *)endColour
    endVector:(NSPoint)endVector
    {
    NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
    NSRect pathBounds;
    CIColor *ciStartColour;
    CIColor *ciEndColour;
    CIVector *ciStartVector;
    CIVector *ciEndVector;
    CIFilter *gradientFilter;
    CIImage *gradientImage;
    CIContext *ciGraphicsContext;

    pathBounds = [self bounds];

    // convert colour space of NSColors
    // core image expects calibrated RGB colours
    startColour = [startColour
    colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
    endColour = [endColour
    colorUsingColorSpaceName:NSCalibratedRGBColorSpace];

    // convert NSColors to CIColors
    ciStartColour = [CIColor colorWithRed:[startColour redComponent]
    green:[startColour greenComponent] blue:[startColour blueComponent]
    alpha:[startColour alphaComponent]];
    ciEndColour = [CIColor colorWithRed:[endColour redComponent] green:
    [endColour greenComponent] blue:[endColour blueComponent] alpha:
    [endColour alphaComponent]];

    // create CIVectors from the NSPoints
    ciStartVector = [CIVector vectorWithX:startVector.x Y:startVector.y];
    ciEndVector = [CIVector vectorWithX:endVector.x Y:endVector.y];

    // create and configure the gradient filter
    gradientFilter = [CIFilter filterWithName:@"CILinearGradient"];
    [gradientFilter setDefaults];
    [gradientFilter setValue:ciStartColour forKey:@"inputColor0"];
    [gradientFilter setValue:ciStartVector forKey:@"inputPoint0"];
    [gradientFilter setValue:ciEndColour forKey:@"inputColor1"];
    [gradientFilter setValue:ciEndVector forKey:@"inputPoint1"];

    // extract the CIImage from the filter pipeline
    gradientImage = [gradientFilter valueForKey:@"outputImage"];

    // save the current graphics state and push a new drawing context
    onto the stack
    [currentContext saveGraphicsState];

    // obtain the current graphics context
    ciGraphicsContext = [currentContext CIContext];

    // clip the context to the bezier path
    [self addClip];

    // draw into the current graphics context
    [ciGraphicsContext drawImage:gradientImage atPoint:CGPointMake
    (pathBounds.origin.x, pathBounds.origin.y) fromRect:CGRectMake
    (pathBounds.origin.x, pathBounds.origin.y, pathBounds.size.width,
    pathBounds.size.height)];

    // restore previous graphics state
    [currentContext restoreGraphicsState];
    }

    What am I doing incorrectly that just happens to work in Tiger, but
    not in Leopard? If I'm drawing an image that an NSView renders, or
    using this code with an NSView that's drawing itself, it doesn't seem
    to make a difference if the view is flipped or not. The gradient is
    always "backwards".

    --
    mikey-san
  • > As of Leopard, when I attempt to draw a linear gradient
    > (CILinearGradient) via any kind of context--an NSImage, an NSView
    > drawing itself (flipped or not), etc--the gradient start and end
    > colours are backwards. That is, if I start the gradient at black and
    > end it at white, it will appear on-screen as though I started at
    > white and ended at black. In Tiger, I did not have this problem.

    http://developer.apple.com/releasenotes/GraphicsImaging/RN-CoreImage/index.
    html


    Core Image Filters Behavior Changes

    Two Core Image filters—CILinearGradient and CILineScreen—behave
    differently on Mac OS X v10.5 as compared to Mac OS X v10.4. These
    changes are implemented in a backwards compatible way. For
    applications compiled on Mac OS X v10.4, these filters continue to
    behave on Mac OS X v10.5 as they did previously. However, for
    applications compiled on Mac OS X v10.5 or later, these filters adopt
    the new behavior:

    CILinearGradient. On Mac OS X v10.4, the gradient incorrectly renders
    inputColor0 at inputPoint1 and inputColor1 at inputPoint0. On Mac OS X
    v10.5, the gradient renders inputColor0 at inputPoint0.
    CILineScreen. The inputSharpness parameter on Mac OS X v10.4 reaches
    maximal sharpness at 0.0, which is inconsistent with all other
    halftone filters (CICircularScreen, CIDotScreen, CIHatchedScreen). On
    Mac OS X v10.5, all halftone filters reach maximal sharpness at 1.0.
  • Thanks for the find!

    However, on second glance, it appears to be somewhat wrong:

    >> These changes are implemented in a backwards compatible way. For
    >> applications compiled on Mac OS X v10.4, these filters continue to
    >> behave on Mac OS X v10.5 as they did previously.

    I can compile a test application on Mac OS X 10.4.10 and the gradient
    will indeed render backwards in 10.5. :-/

    --
    m-s

    On 01 Nov, 2007, at 16:56, Wade Tregaskis wrote:

    >> As of Leopard, when I attempt to draw a linear gradient
    >> (CILinearGradient) via any kind of context--an NSImage, an NSView
    >> drawing itself (flipped or not), etc--the gradient start and end
    >> colours are backwards. That is, if I start the gradient at black
    >> and end it at white, it will appear on-screen as though I started
    >> at white and ended at black. In Tiger, I did not have this problem.
    >
    > http://developer.apple.com/releasenotes/GraphicsImaging/RN-
    > CoreImage/index.html
    >
    > Core Image Filters Behavior Changes
    > Two Core Image filters—CILinearGradient and CILineScreen—behave
    > differently on Mac OS X v10.5 as compared to Mac OS X v10.4. These
    > changes are implemented in a backwards compatible way. For
    > applications compiled on Mac OS X v10.4, these filters continue to
    > behave on Mac OS X v10.5 as they did previously. However, for
    > applications compiled on Mac OS X v10.5 or later, these filters
    > adopt the new behavior:
    >
    > CILinearGradient. On Mac OS X v10.4, the gradient incorrectly
    > renders inputColor0 at inputPoint1 and inputColor1 at inputPoint0.
    > On Mac OS X v10.5, the gradient renders inputColor0 at inputPoint0.
    >
    > CILineScreen. The inputSharpness parameter on Mac OS X v10.4
    > reaches maximal sharpness at 0.0, which is inconsistent with all
    > other halftone filters (CICircularScreen, CIDotScreen,
    > CIHatchedScreen). On Mac OS X v10.5, all halftone filters reach
    > maximal sharpness at 1.0.
  • On Nov 1, 2007, at 7:13 PM, Michael Watson wrote:

    > Thanks for the find!
    >
    > However, on second glance, it appears to be somewhat wrong:
    >
    >>> These changes are implemented in a backwards compatible way. For
    >>> applications compiled on Mac OS X v10.4, these filters continue to
    >>> behave on Mac OS X v10.5 as they did previously.
    >
    > I can compile a test application on Mac OS X 10.4.10 and the
    > gradient will indeed render backwards in 10.5. :-/

    I see the same thing, so the docs seem to be wrong.  I think you just
    have to check the appkit version at runtime and swap the colors,
    regardless of where you link it.

    --
    adam
  • Since CoreImage is not part of AppKit, a fix to CoreImage wouldn't
    necessarily change the AppKit version number.

    Right now, I'm probably going to use Gestalt() to determine whether
    or not my method should flip the CIVectors unless anyone has a better
    idea.

    --
    m-s

    On 01 Nov, 2007, at 22:28, Adam R. Maxwell wrote:

    >
    > On Nov 1, 2007, at 7:13 PM, Michael Watson wrote:
    >
    >> Thanks for the find!
    >>
    >> However, on second glance, it appears to be somewhat wrong:
    >>
    >>>> These changes are implemented in a backwards compatible way. For
    >>>> applications compiled on Mac OS X v10.4, these filters continue
    >>>> to behave on Mac OS X v10.5 as they did previously.
    >>
    >> I can compile a test application on Mac OS X 10.4.10 and the
    >> gradient will indeed render backwards in 10.5. :-/
    >
    > I see the same thing, so the docs seem to be wrong.  I think you
    > just have to check the appkit version at runtime and swap the
    > colors, regardless of where you link it.
    >
    > --
    > adam
    >
  • On Nov 1, 2007, at 8:52 PM, Michael Watson wrote:

    > Since CoreImage is not part of AppKit, a fix to CoreImage wouldn't
    > necessarily change the AppKit version number.

    To clarify: I'll check if(floor(NSAppKitVersionNumber >
    NSAppKitVersionNumber10_4)) to determine if I'm running on Leopard or
    Tiger, since I don't think it's likely that Apple will change
    CoreImage to only reverse gradients when linking on 10.5.

    > Right now, I'm probably going to use Gestalt() to determine whether
    > or not my method should flip the CIVectors unless anyone has a
    > better idea.

    There was an exceedingly long discussion on the merits of Gestalt()
    vs. other version checking methods on macosx-dev a week or so ago.
    It's archived, so hopefully that doesn't start up again here :).

    --
    adam
  • On 02 Nov, 2007, at 00:21, Adam R. Maxwell wrote:

    >
    > On Nov 1, 2007, at 8:52 PM, Michael Watson wrote:
    >
    >> Since CoreImage is not part of AppKit, a fix to CoreImage wouldn't
    >> necessarily change the AppKit version number.
    >
    > To clarify: I'll check if(floor(NSAppKitVersionNumber >
    > NSAppKitVersionNumber10_4)) to determine if I'm running on Leopard
    > or Tiger, since I don't think it's likely that Apple will change
    > CoreImage to only reverse gradients when linking on 10.5.
    >

    Good point. This will also be better than calling Gestalt() every
    single time something rerenders with a gradient.

    It seems that Apple didn't bother defining NSAppKitVersionNumber10_4,
    though. Oops. I'll have to #ifndef/#define it myself.

    >> Right now, I'm probably going to use Gestalt() to determine
    >> whether or not my method should flip the CIVectors unless anyone
    >> has a better idea.
    >
    > There was an exceedingly long discussion on the merits of Gestalt()
    > vs. other version checking methods on macosx-dev a week or so ago.
    > It's archived, so hopefully that doesn't start up again here :).

    I'll go have a look at that, then, and make sure to come back and
    kick up a dust storm. ;-)

    (Or I could simply read it.)

    --
    m-s
  • >>> These changes are implemented in a backwards compatible way. For
    >>> applications compiled on Mac OS X v10.4, these filters continue
    >>> to behave on Mac OS X v10.5 as they did previously.
    >
    > I can compile a test application on Mac OS X 10.4.10 and the
    > gradient will indeed render backwards in 10.5. :-/

    Please file a bug report for this, then; I'm pretty sure the
    documentation is [supposed to be] correct in this matter.

    Wade
previous month november 2007 next month
MTWTFSS
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30    
Go to today