2

I have a CGPath shaped like an arrow that I am drawing in the CGContext of my current view. I would like to generate a miniature version (thumbnail) of the arrow to add it as an Image to a UITableView showing all selected arrows.

I am succeeding to downscale a picture of the full context which leaves the arrow smaller than it should be. Ideally I would like to crop the image of the full context to the bounds of the arrow. However, I was not yet successful. Any leads? Thanks for the help!

Here are a picture of the full view containing an arrow and another picture of the thumbnail I am generating. enter image description here enter image description here

Ideally the thumbnail above would be cropped to contain the arrow only - not the full context.

The code I use is the follwoing:

- (UIImage*) imageForObject:(id<GraphicalObject>) object 
                     inRect:(CGRect)rect {

    UIImage *image = [UIImage new];
    CGRect objectBounds = [object objectBounds];
    UIGraphicsBeginImageContext(self.view.frame.size);//objectBounds.size);
    CGContextRef context =UIGraphicsGetCurrentContext();
    [object drawInContext:context];
    //doesn't work 
    CGContextClipToRect(context, objectBounds);

    image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return image;
}
Haroldo Gondim
  • 7,725
  • 9
  • 43
  • 62
user1612877
  • 391
  • 1
  • 5
  • 19

1 Answers1

0

The CGRect called objectBounds has two components, an origin and a size. In order the draw the object correctly as a thumbnail, the code needs to scale the image (to get the size right) and translate the image (to move the origin to {0,0}). So the code looks like this

- (UIImage *)getThumbnailOfSize:(CGSize)size forObject:(UIBezierPath *)object
{
    // to maintain the aspect ratio, we need to compute the scale
    // factors for x and y, and then use the smaller of the two
    CGFloat xscale = size.width / object.bounds.size.width;
    CGFloat yscale = size.height / object.bounds.size.height;
    CGFloat scale = (xscale < yscale) ? xscale : yscale;

    // start a graphics context with the thumbnail size
    UIGraphicsBeginImageContext( size );
    CGContextRef context = UIGraphicsGetCurrentContext();

    // here's where we scale and translate to make the image fit
    CGContextScaleCTM( context, scale, scale );
    CGContextTranslateCTM( context, -object.bounds.origin.x, -object.bounds.origin.y );

    // draw the object and get the resulting image
    [object stroke];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return image;
}
user3386109
  • 34,287
  • 7
  • 49
  • 68
  • Thanks - this works for the cgpath - however then I will stil need to fill it wil a gradient. – user1612877 Aug 06 '15 at 06:17
  • @user1612877 Use `[object drawInContext:context]` instead of `[object stroke]`. I was using a simple `UIBezierPath` to test, since I don't have the code that draws the arrow. – user3386109 Aug 06 '15 at 07:14
  • 1
    Thanks - that works for me. For expediency's sake I would like to say that I had to distinguish between four cases when drawing the arrow where depending on the quadrant the arrow points to, the CGContextTranslateCTM()-function's last two arguments needed to change between all possible combinations of 0/-objectBounds.origin.x, 0/-objectBounds.origin.y – user1612877 Aug 06 '15 at 21:05