3

I've got an inherited project with a bunch of code that uses -[UIImage imageWithContentsOfFile:] and a full path. I'm converting it to use -[UIImage imageNamed:] and just the file name (no extension) so I can pass it things like @"icon" and get either icon.png or icon@2x.png or icon~ipad.png, as appropriate.

The problem is, there's a part in the program where I want to check the size of the image and, if it's too big, I want to display, instead, TooBigImage.png.

So I need to know, if I call [UIImage imageNamed: someName], which extended/modified name it's going to use. Basically, I want the path to that file, so I can check it's size before loading the image.

Alternately, if there's a way to check imageSizeForImageNamed: or something similar, I'm ok using that, I just don't know of any.

I'd rather NOT re-implement the whole "if retina, append @2x, etc..." thing, as that's (a) cumbersome and (b) fragile (what if Apple changes/augments the behaviour?)

Hints?

Thanks!

Olie
  • 24,597
  • 18
  • 99
  • 131
  • When you say size, do you mean the size in pixel dimensions or in bytes? – idz Jul 11 '12 at 21:40
  • I don't want to step on your toes, but `[UIImage imageNamed]` should only ever be used for UI icon images as it caches the retrieved images in RAM which can cause memory problems (if used wrongly). On the other hand `[UIImage imageWithContentsOfFile]` doesn't do caching which is desirable for larger images. – Torsten Walter Jul 11 '12 at 22:08
  • @ids: either. @Torsten: I believe you are mistaken about not using `imageNamed`. System cacheing is fine, and the leaks from earlier iOSs have long been fixed. – Olie Jul 12 '12 at 01:02
  • Still, you don't want to keep images longer in Ram then needed. If it's fine for your case then so be it. IMHO the easiest way and not at all fragile would be to to query the interface idiom and the scale factor and calculate your images sizes based on that. You'd have to revisit this code if new devices come out, but you might have to anyway to adjust other aspects of your app. – Torsten Walter Jul 12 '12 at 15:26
  • Is there a reason if (image.size.width > 1000) blah blah; would not work here? After the appropriate image is set the UIImage will contain the size property of the loaded image. – Mark McCorkle Dec 20 '12 at 21:51

3 Answers3

0

For pixels use size and scale properties:

UIImage *getMySize = [UIImage imageNamed:@"blah"];

float width = getMySize.scale * getMySize.size.width;

float height = getMySize.scale * getMySize.size.height;

Here is the UIImage Documentation.

Justin Paulson
  • 4,388
  • 1
  • 23
  • 28
  • Right. I was wondering if there's a solution that gives me the name of the file that will be used by `imageNamed:`, so I can check file stats on it without loading it. – Olie Jul 12 '12 at 01:05
  • Well, once you have the pixel size, you should be able to determine which file it is returning unless you have multiple files name "blah*.png" that are the same size in your main bundle. When you have so much control over the main bundle it shouldn't be too hard to use the size information and backtrack to figure out which of your files it is using. – Justin Paulson Jul 12 '12 at 11:12
-1

As far as I know you should implement your own function to check the size of the file manually.

You can generate the names by yourself like:

-(bool)fileOk:(NSString*)filename
{
    bool retina = [UIScreen mainScreen].scale == 2.0;
    static bool iPad = UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPad;

    //Generate the filename
    NSString *fullFilename = [NSString stringWithFormat:@"%@%@%@",filename,(retina)?@"@2x":@"",(iPad)?@"~ipad":@"~iphone"]; 

    //Get the size:

    NSError *error;
    NSString *fullPath=[[NSBundle mainBundle] pathForResource:fullFilename ofType:@"png"];
    NSDictionary *fileDictionary = [[NSFileManager defaultManager] attributesOfItemAtPath: fullPath error:&error];

    return (fileDictionary && [fileDictionary fileSize]<SOME_TO_BIG_SIZE_CONSTANT);
}

Then you can choose if you want to show the image or not. I have not tried the code so there may be some typo... I hope that this is what you where looking for...

  • This has the problem that I mentioned in my question of fragility. (As posted, it's also buggy, but I'll leave that as an exercise. ;) – Olie Jul 12 '12 at 01:12
  • Well I edited so it does the trick of detecting if the file exists. The fileDictionary will be nil if the file does not exist. I see yours as as a very easy problem to solve to be wandering so much about it... – Carles Estevadeordal Jul 12 '12 at 10:35
-1

[UIImage imageNamed: @"icon"] always looks in the applications main bundle. So icon.png must be located right in the bundle to be found. No subpath is allowed there.

However, you can defined your own bundles by using [NSBundle bundleWithPath: @"subfolder"] the advantage here is that you can then use the bundle methods to retrieve optimized assets.

NSBundle *bundle = [[NSBundle bundleWithPath: @"folder"] autorelease];

Then, [bundle pathForResource:ofType:] will return the correct image resource path from your folder (i.e. icon~ipad) and [UIImage imageWithContentsOfFile:] will take care of the size modifier.

Although this question does not have an answer it summarizes my experiences with this quit well. How do NSBundle pathForResource:ofType: and UIImage imageWithContentsOfFile: handle scale and device modifiers?

Community
  • 1
  • 1
Torsten Walter
  • 5,614
  • 23
  • 26
  • Yes, `imageNamed` always looks in the main bundle, but it does not always load "icon.png" -- that's what this question is about: can I determine what file will be loaded? – Olie Jul 12 '12 at 01:13
  • It will load the most appropriate resource. By definition the function loads the png image with the given name from the root folder of the bundle. There is no way (that I am aware of) too tell this function to load another image. The function though is smart enough to load the iPhone/ipad and/or @2x images if present. – Torsten Walter Jul 12 '12 at 14:47