views:

216

answers:

3

I've created a custom view class and right now just want to draw an image scaled to fit the view, given a UIImage. I tried just drawing the UIImage.CGImage, but as others have attested to on this site (and in the docs), that renders the image upside down.

So, at the suggestion of an answer I found to another question, I'm trying to draw it directly, but nothing is rendering in the view and I'm not sure why. Here's my drawing code:

- (void)drawRect:(CGRect)rect {
    // Drawing code
    [super drawRect:rect];

    if (self.originalImage) {
        [self drawImage];
    }
}

- (void) drawImage {
    if (CGSizeEqualToSize(originalImage.size, self.frame.size) == NO) {
        CGFloat scaleFactor = 1.0;
        CGFloat scaledWidth = 0.0;
        CGFloat scaledHeight = 0.0;
        CGPoint thumbPoint = CGPointMake(0.0, 0.0);

        CGFloat widthFactor = self.frame.size.width / originalImage.size.width;
        CGFloat heightFactor = self.frame.size.height / originalImage.size.height;

        if (widthFactor < heightFactor) {
            scaleFactor = widthFactor;
        } else {
            scaleFactor = heightFactor;
        }

        scaledWidth = originalImage.size.width * scaleFactor;
        scaledHeight = originalImage.size.height * scaleFactor;

        if (widthFactor < heightFactor) {
            thumbPoint.y = (self.frame.size.height - scaledHeight) * 0.5;
        } else if (widthFactor > heightFactor) {
            thumbPoint.x = (self.frame.size.width - scaledWidth) * 0.5;
        }

        UIGraphicsBeginImageContext(self.frame.size);
        CGRect thumbRect = CGRectZero;
        thumbRect.origin = thumbPoint;
        thumbRect.size.width = scaledWidth;
        thumbRect.size.height = scaledHeight;

        [originalImage drawInRect:thumbRect];
        self.scaledImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    } else {
        self.scaledImage = originalImage;
    }   
}

My understanding (after studying this a bit) is that the UIGraphicsBeginImageContext function creates an offscreen for me to draw into, so now how do I render that context on top of the original one?

A: 

If you want to draw a UIImage, use a UIImageView. It was written to do that for you.

Paul Lynch
I intend to do a bit a custom drawing, and the docs indicate that because subclasses of UIImageView can't receive the drawRect message custom drawing should be done in subclasses of UIView.
Ben Collins
There are cases where you should draw an image directly. But you can just use the UIImageView as a subview of your own custom view.
Paul Lynch
+1  A: 

I commended out the calls to GraphicsBegin and GraphicsEnd and the image renders - but many things that I read indicated that one should create a graphics context in this way.

If those were the names, then it would make sense that you would need to call them before and after drawing.

But those are not the names. The full names of the functions, as you used them in your code, are:

  • UIGraphicsBeginImageContext
  • UIGraphicsEndImageContext

These names hint that these functions are for a specific kind of drawing, and the documentation backs that up:

You use this function to configure the drawing environment for rendering into a bitmap. …

While the context created by this function is the current context, you can call the UIGraphicsGetImageFromCurrentImageContext function to retrieve an image object based on the current contents of the context.

That is what these functions are for: Making a new image by capturing some drawing.

Your situation is different: You already have an image, and you are a view that has been called upon to draw. This means that you already have a current context, and you need only to draw into it.

So, don't create a context—just draw.

Peter Hosey
A: 

The function you named drawImage should be named createScaledImage, as all it does is create scaledImage. To draw scaledImage, try

[scaledImage drawAtPoint:self.frame.origin];

You would be better served by sticking originalImage or scaledImage in a UIImageView with the contentMode set to UIViewContentModeScaleAspectFit. UIImageView will basically do exactly what you have coded there, but it gets access to whatever caching and fast drawing Apple does behind the scenes.

drawnonward