4

I tried many many ways to draw a black outline around image.
This is an example of the result I want:

enter image description here

Can someone please let me know how should I do it? or give me an example ?

Edit: i stuck in here: can someone please help me finish it ? What i did was to make another shape in black color under the the white with shadow and then fill it all in black so it will be like an outline - but i cant figure out how to make the last and important part of making the shadow and fill it to be all in black.

- (IBAction)addStroke:(id)sender{

    [iconStrokeTest setImage:[self makeIconStroke:icon.imageView.image]];

}

- (UIImage *)makeIconStroke:(UIImage *)image{
    CGImageRef originalImage = [image CGImage];
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef bitmapContext = CGBitmapContextCreate(NULL,
                                                       CGImageGetWidth(originalImage),
                                                       CGImageGetHeight(originalImage),
                                                       8,
                                                       CGImageGetWidth(originalImage)*4,
                                                       colorSpace,
                                                       kCGImageAlphaPremultipliedLast);

    CGContextDrawImage(bitmapContext, CGRectMake(0, 0, CGBitmapContextGetWidth(bitmapContext), CGBitmapContextGetHeight(bitmapContext)), originalImage);

    CGImageRef finalMaskImage = [self createMaskWithImageAlpha:bitmapContext];

    UIImage *result = [UIImage imageWithCGImage:finalMaskImage];

    CGContextRelease(bitmapContext);
    CGImageRelease(finalMaskImage);

    // begin a new image context, to draw our colored image onto
    UIGraphicsBeginImageContext(result.size);

    // get a reference to that context we created
    CGContextRef context = UIGraphicsGetCurrentContext();

    // set the fill color
    [[UIColor blackColor] setFill];

    // translate/flip the graphics context (for transforming from CG* coords to UI* coords
    CGContextTranslateCTM(context, 0, result.size.height);
    CGContextScaleCTM(context, 1.0, -1.0);

    // set the blend mode to color burn, and the original image
    CGContextSetBlendMode(context, kCGBlendModeColorBurn);
    CGRect rect = CGRectMake(0, 0, result.size.width, result.size.height);
    CGContextDrawImage(context, rect, result.CGImage);

    // set a mask that matches the shape of the image, then draw (color burn) a colored rectangle
    CGContextClipToMask(context, rect, result.CGImage);
    CGContextAddRect(context, rect);
    CGContextDrawPath(context,kCGPathFill);

    // generate a new UIImage from the graphics context we drew onto
    UIImage *coloredImg = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    //return the color-burned image
    return coloredImg;

}

- (CGImageRef)createMaskWithImageAlpha:(CGContextRef)originalImageContext {

    UInt8 *data = (UInt8 *)CGBitmapContextGetData(originalImageContext);

    float width = CGBitmapContextGetBytesPerRow(originalImageContext) / 4;
    float height = CGBitmapContextGetHeight(originalImageContext);

    int strideLength = ROUND_UP(width * 1, 4);
    unsigned char * alphaData = (unsigned char * )calloc(strideLength * height, 1);
    CGContextRef alphaOnlyContext = CGBitmapContextCreate(alphaData,
                                                          width,
                                                          height,
                                                          8,
                                                          strideLength,
                                                          NULL,
                                                          kCGImageAlphaOnly);

    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            unsigned char val = data[y*(int)width*4 + x*4 + 3];
            val = 255 - val;
            alphaData[y*strideLength + x] = val;
        }
    }

    CGImageRef alphaMaskImage = CGBitmapContextCreateImage(alphaOnlyContext);
    CGContextRelease(alphaOnlyContext);
    free(alphaData);

    // Make a mask
    CGImageRef finalMaskImage = CGImageMaskCreate(CGImageGetWidth(alphaMaskImage),
                                                  CGImageGetHeight(alphaMaskImage),
                                                  CGImageGetBitsPerComponent(alphaMaskImage),
                                                  CGImageGetBitsPerPixel(alphaMaskImage),
                                                  CGImageGetBytesPerRow(alphaMaskImage),
                                                  CGImageGetDataProvider(alphaMaskImage),     NULL, false);
    CGImageRelease(alphaMaskImage);

    return finalMaskImage;
} 
Amir Foghel
  • 853
  • 1
  • 12
  • 28

1 Answers1

1

Well, theres no build-in API for that. You'll have to do it yourself or find a libary for this. But you could "fake" the effect by drawing the image with a shadow. Note that shadows can be any color, it doesn't have to look like a shadow. This would be the easiest way.

Other than that you could vectorize the raster image and stroke that path. Core image's edge detection filter will help for that but it could turn out to be hard to acomplish.

Nenad M
  • 3,055
  • 20
  • 26
  • Hi Nenad, First of all thank you for the comment. i've searched in the last 2 days the way to do what you say and can find out how - in the basics i know what i need to do - but i don't know how. can you please explain the shadow solution because i tried and the result wasn't good. – Amir Foghel Oct 20 '12 at 13:30
  • 1
    Hi Amir! I didn't try this out for myself, but the way i would try to get the shadow over the image is to make a inverse mask from the image, clip to that mask ([CGContextClipToMask](http://developer.apple.com/library/mac/#documentation/GraphicsImaging/Reference/CGContext/Reference/reference.html#//apple_ref/c/func/CGContextClipToMask)) and then fill with any solid collor (i.e. background) with shadow applied. To make the mask create a CGBitmapContext, draw the image into it, set the blend mode to "Source In", fill with black, set the blend mode to "Destination Atop" and fill with white. – Nenad M Oct 20 '12 at 18:39
  • Hi my friend, Thanks for the replay- i'm going to try this now. coming later with answer (and working code.. i hope). – Amir Foghel Oct 20 '12 at 18:59
  • Hi there, can you please look at the code i just added to the main post and try to help me finish it ? – Amir Foghel Oct 20 '12 at 19:56
  • Hi Amir! I'ts getting late here in Vienna! :) Check out [this tutorioal](http://www.raywenderlich.com/2079/core-graphics-101-shadows-and-gloss) for drawing shadows in CG. – Nenad M Oct 20 '12 at 20:56
  • i missing something. please if you can make me a basic sample - i will appreciate it ! – Amir Foghel Oct 21 '12 at 00:16