 |
 |
Image composition: the dreaded "fringe"
|
 |
|
 |
|
Dedicated MacNNer
Join Date: Apr 2001
Location: San Francisco, USA
Status:
Offline
|
|
A cool feature of Quartz is that it anti-aliases clipping regions. Well, I thought it was cool until I started using it. Now I'm running into the "fringe" problem.
Let's say I cut a circle out of an image. Now I've got an image of a circle and an image with a corresponding hole. When I put the two back together, I should be back where I started, right? Nope. Example:
<BLOCKQUOTE><font size="1"face="Geneva, Verdana, Arial">code:</font><HR><pre><font size=1 face=courier>NSBezierPath *path = [NSBezierPath bezierPathWithOvalInRect:NSMakeRect(<font color = blue>0</font>,<font color = blue>0</font>,<font color = blue>32</font>,<font color = blue>32</font>)];
NSImage *appIcon = [NSImage imageNamed:<font color = orange>@"NSApplicationIcon"</font>];
NSImage *emptyImage = [[NSImage alloc] initWithSize:[appIcon size]];
<font color = brown>// Copy a circular slice of the appIcon into emptyImage</font>
[emptyImage lockFocus];
[path setClip];
[appIcon compositeToPoint:NSMakePoint( <font color = blue>0</font>, <font color = blue>0</font> ) operation:NSCompositeSourceOver];
[emptyImage unlockFocus];
<font color = brown>// Erase the same circle from appIcon</font>
[appIcon lockFocus];
[path setClip];
[emptyImage compositeToPoint:NSMakePoint( <font color = blue>0</font>, <font color = blue>0</font> ) operation:NSCompositeClear];
[appIcon unlockFocus];
<font color = brown>// Put the pieces back together</font>
[appIcon lockFocus];
[emptyImage compositeToPoint:NSMakePoint( <font color = blue>0</font>, <font color = blue>0</font> ) operation:NSCompositeSourceOver];
[appIcon unlockFocus];
</font>[/code]
Here is the result (enlarged). Notice the faint white circular fringe.
I'm working on a photo editor in Cocoa where you can select portions of an image and move them around. Everything works great except for these darned fringes. I've tried different combinations of composite operations with the same result.
Any suggestions?
TIA
[ 07-04-2001: Message edited by: honeydew ]
|
|
|
| |
|
|
|
 |
|
 |
|
Mac Enthusiast
Join Date: Feb 2000
Location: Storrs,Connecticut, USA
Status:
Offline
|
|
CGContextSetShouldAntialias([[NSGraphicsContext currentContext] graphicsPort], NO);
That will get rid of anti-aliasing. If you really want to keep antialiasing, then here's a way that you could do it in order to also be able to undo it:
1. Once the user selects a circle, make a copy of either the circle itself, or the entire square that the circle fits in.
Note: You can get access to the data via the - (unsigned char *)bitmapData method of NSBitmapImageRep. The data will be a 1 dimensional array of rgb or rgba structures. The value of each element of a pixel, r,g,b or a is an unsigned char. values range from 0 to 255. Do not free the data when you are done because then NSBitmapImageRep can no longer use it. This is assuming no compression of the data. If the data is compressed then I don't know how to deal with it. Changes made to that data will change the image: you don't have a copy.
2. Now, take the circle that is selected, the same way that you did before, and make a new subview with it.
3. Draw the circle in the image black or whatever the background color is. (This is why you wanted to back it up: so that you still have the data should you wish to undo what you did.
4. As the user drags around the cut out circle, just move the location of the circle in the subview.
5. When the user drops it, first backup the portion of the image that they wish to cover. Now, you now have a choice. You can either drop the anti-aliased thing which is the subview back into the image, or you can drop the original image back in. I'd suggest either dropping the antialiased thing back so you get a WYSIWYG approach to things, or you always drag a non anti-aliased image.
The reason for backing up stuff is that you can implement undo and not backup the entire image everytime. That would be bad if the image is big.
Some thought's about NSImageViews: They suck. Example: open a 4096 X 3072 image in Preview. It takes a second to load, but then you can scroll around just fine. Now, write your own version of Preview. Just use an NSImageView in an NSScrollView. Should be fine, right? I mean Apple wrote it; it should be just like they use in preview. Wrong. Apple uses a subclass of NSImageView in preview. (Check the nib file to see.) Using an NSImageView with such a large image is really terrible. I mean, it must try to redraw the entire image everytime that it is told to resize etc. It is painfully slow. This is true even if you have setCopiesOnScroll: set to YES. Moral: NSImageViews are crappier then they can be. (a la preview)
|
|
|
| |
|
|
|
 |
|
 |
|
Dedicated MacNNer
Join Date: Apr 2001
Location: San Francisco, USA
Status:
Offline
|
|
Dalgo, thanks for the excellent response.
Oddly enough, I fixed my problem by changing a single constant. I'm not sure exactly why it works, but it does. When putting the two images back together, I set the composition operation to NSCompositePlusLighter. No more fringe!
<BLOCKQUOTE><font size="1"face="Geneva, Verdana, Arial">code:</font><HR><pre><font size=1 face=courier><font color = brown>// Put the pieces back together</font>
[appIcon lockFocus];
[emptyImage compositeToPoint:NSMakePoint( <font color = blue>0</font>, <font color = blue>0</font> ) operation:NSCompositePlusLighter];
[appIcon unlockFocus];
</font>[/code]
[ 07-04-2001: Message edited by: honeydew ]
|
|
|
| |
|
|
|
 |
|
 |
|
Dedicated MacNNer
Join Date: Jan 2001
Location: Virginia, US
Status:
Offline
|
|
[[NSGraphicsContext currentContext] setShouldAntialias:NO]
achieves the same thing as the CoreGraphics call...
You also might play with the NSImageInterpolation settings in NSGraphicsContext; I'm not complete sure what those do yet so I don't know if that will help or not. Turning off antialiasing would work though.
I suppose you could cut out a slightly larger portion with antialiasing turned off, then use antialiasing to display the "hole", then use NSCompositeCopy to put the original, slightly larger bit back. I think this is pretty much what Dalgo was suggesting -- he was just using the bounding-box rectangle, which would also likely work.
|
|
|
| |
|
|
|
 |
 |
|
 |
|
|
|
|
|

|
|
 |
Forum Rules
|
 |
 |
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
|
HTML code is Off
|
|
|
|
|
|
 |
 |
 |
 |
|
 |
|