Wow, Ken! It works like magic (the second method I mean). Thank you
very much. I think I would never guess it myself.

For those who will reuse this code, don't forget to save/restore the
graphics context because CGContextClipToMask modified the clipping
region.

Sorry for late thanking, I had to postpone this task for a while.

Oleg Krupnov.


On Sun, Feb 1, 2009 at 4:03 AM, Ken Ferry <kenfe...@gmail.com> wrote:
> All else aside, yes you can do this in Cocoa and/or Quartz.
> Here are a couple different ways.  For instruction's sake, here's it done
> with a compositing operation, NSCompositeDestinationIn.  Result color =
> what's already in the context but with additional alpha taken from the new
> drawing.
>
> - (void)drawRect:(NSRect)dirtyRect {
>     NSRect bounds = [self bounds];
>     NSImage *textLayerImage = [[NSImage alloc] initWithSize:bounds.size]; {
>         [textLayerImage lockFocus]; {
>             NSRect textLayerBounds = {NSZeroPoint, [textLayerImage size]};
>
>             [@"I am a string" drawAtPoint:textLayerBounds.origin
> withAttributes:nil];
>
>             NSGradient *alphaGradient = [[NSGradient alloc]
> initWithStartingColor:[NSColor blackColor] endingColor:[NSColor
> clearColor]]; {
>                 [[NSGraphicsContext currentContext]
> setCompositingOperation:NSCompositeDestinationIn];
>                 [alphaGradient drawInRect:textLayerBounds angle:0];
>             } [alphaGradient release];
>         } [textLayerImage unlockFocus];
>
>         [textLayerImage drawInRect:bounds fromRect:NSZeroRect/*whole thing*/
> operation:NSCompositeSourceOver fraction:1.0];
>     } [textLayerImage release];
> }
>
> That works, but it loses the LCD antialiasing, as others have noticed.  The
> text is drawn into a transparent layer, which defeats subpixel rendering.
>  Also, most people will not understand your code, because of the use of
> NSCompositeDestinationIn.
> A more understandable method that will also preserve the LCD text is to set
> a clip that has partial transparency.  This requires mixing CoreGraphics
> calls in with the Cocoa.
>
> - (void)drawRect:(NSRect)dirtyRect {
>     CGContextRef ctx = [[NSGraphicsContext currentContext] graphicsPort];
>     NSRect bounds = [self bounds];
>
>     CGImageRef maskImage = CreateMaskImage(bounds.size); {
>         CGContextClipToMask(ctx, NSRectToCGRect(bounds), maskImage);
>     } CFRelease(maskImage);
>
>     [@"I am a string" drawAtPoint:[self bounds].origin withAttributes:nil];
> }
>
> CGImageRef CreateMaskImage(NSSize size) {
>
>     CGImageRef maskImage;
>
>     CGContextRef maskContext = CGBitmapContextCreate(NULL, size.width,
> size.height, 8/*bitsPerComponent*/, 0/*bytesPerRow - 0 means CG picks*/,
> [[NSColorSpace genericGrayColorSpace] CGColorSpace], kCGImageAlphaNone); {
>
>         CGGradientRef grayGradient =
> CGGradientCreateWithColors([[NSColorSpace genericGrayColorSpace]
> CGColorSpace], (CFArrayRef)[NSArray
> arrayWithObjects:(id)CGColorGetConstantColor(kCGColorWhite),
> (id)CGColorGetConstantColor(kCGColorBlack), nil], NULL/*locations - NULL
> means colors evenly distribute*/); {
>
>             CGContextDrawLinearGradient(maskContext, grayGradient,
> CGPointZero, CGPointMake(CGBitmapContextGetWidth(maskContext), 0),
> 0/*options*/);
>
>         } CFRelease(grayGradient);
>
>
>
>         maskImage = CGBitmapContextCreateImage(maskContext);
>
>
>
>     } CFRelease(maskContext);
>
>
>
>     return maskImage;
>
> }
>
> CoreImage is likely to not perform well for a small task like this.
>  CoreImage incurs some per-use costs that it makes up for with awesome
> per-pixel performance.  If you don't have very many pixels and your effect
> is simple enough to do with Cocoa/CoreGraphics, the CoreGraphics approach is
> likely to perform better.
> -Ken
>
> On Thu, Jan 29, 2009 at 12:27 AM, Oleg Krupnov <oleg.krup...@gmail.com>
> wrote:
>>
>> Yeah, the question is however how do I technically (e.g. in Cocoa)
>> composite the "appropriate alpha" with an image, whether the
>> background image, as you suggest, or with text image, as Ricky
>> suggested.
>>
>> AFAIU, there is not such NSCompositingOperation to do this trick. It
>> appears that I need to iterate all pixels of the intermediate bitmap,
>> and multiply the transparency value by the mask. This is quite
>> low-level, is there a better way?
>>
>>
>> On Thu, Jan 29, 2009 at 8:32 AM, Kyle Sluder <kyle.slu...@gmail.com>
>> wrote:
>> > On Wed, Jan 28, 2009 at 10:57 AM, Thomas Davie <tom.da...@gmail.com>
>> > wrote:
>> >> This solution will also throw sub-pixel anti-aliasing in the bin.
>> >
>> > Perhaps the better solution is to draw the text as normal and then
>> > re-draw the background with the appropriate alpha on top.
>> >
>> > --Kyle Sluder
>> >
>> _______________________________________________
>>
>> Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)
>>
>> Please do not post admin requests or moderator comments to the list.
>> Contact the moderators at cocoa-dev-admins(at)lists.apple.com
>>
>> Help/Unsubscribe/Update your Subscription:
>> http://lists.apple.com/mailman/options/cocoa-dev/kenferry%40gmail.com
>>
>> This email sent to kenfe...@gmail.com
>
>
_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to