Denis Masyukov
Denis Masyukov

Reputation: 3072

UIImageView blurs image

I have a really weird problem with UIImageView. I have an image (an RGB png) 45x45 pixels which I add to the view. I can see that image is blurred after added to the view. Here is the same image in the simulator (left) and in Xcode (right):

alt text
(source: partywithvika.com)

alt text
(source: partywithvika.com)

I have custom UIImageView class with this initWithImage code:

- (id) initWithImage:(UIImage*) image {
    self = [super initWithImage:image];

    self.frame = CGRectMake(0, 0, 45, 45);
    self.contentMode = UIViewContentModeScaleAspectFit;

    self.quantity = 1;
    if (self) {
        self.label = [[UITextField alloc]initWithFrame:CGRectMake(0,40,45,25)];
        self.label.font = [UIFont systemFontOfSize:16];
        self.label.borderStyle = UITextBorderStyleNone;
        self.label.enabled = TRUE;
        self.label.userInteractionEnabled = TRUE;
        self.label.delegate = self;
        self.label.keyboardType = UIKeyboardTypeNumbersAndPunctuation;
        self.label.textAlignment = UITextAlignmentCenter;
    }
    self.userInteractionEnabled = TRUE;

    // Prepare 3 buttons: count up, count down, and delete
    self.deleteButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    self.deleteButton.hidden = NO;
    self.deleteButton.userInteractionEnabled = YES;
    self.deleteButton.titleLabel.font  = [UIFont systemFontOfSize:20];
    self.deleteButton.titleLabel.textColor = [UIColor redColor];
    [self.deleteButton setTitle:@"X" forState:UIControlStateNormal];
    [self.deleteButton addTarget:self action:@selector(deleteIcon:) forControlEvents:UIControlEventTouchUpInside];

    self.upCountButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    self.upCountButton.hidden = NO;
    self.upCountButton.userInteractionEnabled = YES;
    [self.upCountButton setTitle:@"+" forState:UIControlStateNormal];
    [self.upCountButton addTarget:self action:@selector(addQuantity:) forControlEvents:UIControlEventTouchUpInside];

    self.downCountButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    self.downCountButton.hidden = YES;
    self.downCountButton.userInteractionEnabled = YES;
    [self.downCountButton setTitle:@"-" forState:UIControlStateNormal];
    [self.downCountButton addTarget:self action:@selector(removeQuantity:) forControlEvents:UIControlEventTouchUpInside];
    return self;
}

I create it like this:

UIImage *desertIcon = [UIImage imageNamed:@"desert.png"];
IconObj *desertIconView = [[IconObj alloc] initWithImage:desertIcon];
desertIconView.center = CGPointMake(265,VERTICAL_POINT_ICON);
desertIconView.type = [IconObj TYPE_DESERT];
[self.view addSubview:desertIconView];
[desertIconView release];

Why would the displayed image be so than the one stored in a file?

Upvotes: 5

Views: 8492

Answers (7)

CarlJ
CarlJ

Reputation: 9481

complete source for the offset problem:

  contentImage  = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];

  UIImage *cImage = [UIImage imageNamed:image];
  self.contentImage.image = cImage;

  [self.contentImage setFrame:CGRectMake(0, 0, cImage.size.width, cImage.size.height)];

  CGFloat offset = 0.0f;

  if ( ( (int)cImage.size.width % 2 ) && ( (int)cImage.size.height % 2 ) ) {
    offset = 0.5f;
  }

  [self.contentImage setCenter:CGPointMake(256.0f + offset, 256.0f + offset)];

Upvotes: 0

me1974
me1974

Reputation: 99

I just had the same problem. First I thought wtf do I need glasses?

Then I realized it´s just not possible to center an image (or label) when you give it an odd number. You need to resize your image to e.g. 46*46 if you want to center it and stay sharp.

Or you can leave it at 45*45 but then you need to decide whether you want your image to be mal-centered 1 pixel to the right, or 1 pixel to the left. (or leave it blurry).

Upvotes: 1

iwat
iwat

Reputation: 3851

Your IconObj is 45 pixels wide. You move your IconObj center to 265 which makes its frame to (242.5, VERTICAL_POINT_ICON - 25*0.5, 45, 25). Image will always be blur if some of frame parameter is not integer.

Solution, calculate the frame parameter yourself (don't use center). And always make it integer (cast to NSInteger, use ceil, floor, or round).

desertIconView.frame = CGRectMake((NSInteger)(265 - 45*0.5),
                                  (NSInteger)(VERTICAL_POINT_ICON - 25*0.5),
                                  45, 25);

Upvotes: 3

Adam Kaplan
Adam Kaplan

Reputation: 1962

In general, everything you do on iPhone with UIKit should be pixel-aligned. Problems with pixel alignment usually manifest as blurriness (this is especially true with text and images). This is why when I find blurry view, I first check if I'm setting the center property. When you set center, the frame's x, y, height and width are adjusted around that center point... frequently resulting in fractional values.

You could try using CGRectIntegral on the frame as shown:

desertIconView.center = CGPointMake(265,VERTICAL_POINT_ICON);
desertIconView.frame = CGRectIntegral(desertIconView.frame);

This may work, but if it doesn't, try setting the frame manually, without using center property to ensure that no values are fractional.

Edit: Whoops! Didn't notice that the OP had answered his own question... I'll leave this up for informational reasons anyway.

Upvotes: 8

Pillis
Pillis

Reputation: 31

I had this problem and it was driving me nuts. After some investigation it turned out that my image was smaller than the frame, and hence the scaling up blurred it. Once I had put in higher resolution images the problem is gone.

Make sure your image size is greater than your UIImageView frame size.

Upvotes: 3

Denis Masyukov
Denis Masyukov

Reputation: 3072

What I ended up doing is loading bigger picture into 45x45 UIImageView, of course with

contentMode = UIViewContentModeScaleAspectFit;

Upvotes: 1

Nikolai Ruhe
Nikolai Ruhe

Reputation: 81878

Try to align your IconObj view at screen pixels. If it's really 45x45 then you should set the center to something like CGPointMake(x + 0.5f, y + 0.5f).

You should also double check image size in pixels (e.g in Preview.app Command-I).

Upvotes: 0

Related Questions