With the retina we make images with the #2x in the name. I see where the default image has to be default-568h#2x but this does not seem to be the case for other images. Like if my background is bg.png and bg#2x.png I tried using bg-568h#2x.png but that does not work. Can somebody tell me what the images need to be named to support the iPhone 5?
No special suffix for iPhone 5 (4'' display), just the specific Default-568h#2x.png file.
Here's a macro to handle it:
// iPhone 5 support
#define ASSET_BY_SCREEN_HEIGHT(regular, longScreen) (([[UIScreen mainScreen] bounds].size.height <= 480.0) ? regular : longScreen)
Usage: (assets names - image.png, image#2x.png, image-568h#2x.png)
myImage = [UIImage imageNamed:ASSET_BY_SCREEN_HEIGHT(#"image",#"image-568h")];
There is no specific image name. Having the Default-568h#2x will launch that image on an iPhone 5 or iPod Touch 5G and will enable the non-letterbox mode. After that, you need to design your views to be flexible. There is no special "image name" or anything for the new size.
For your background, for example, you should probably be using an image that is capable of stretching or tiling and have it configured properly before setting it.
iPhone 5 does not have a different pixel density, it's the same retina display PPI as the iPhone 4/4S, it's just a different screen size. The #2x images will be used on iPhone 5 as well as 4/4S.
To complete Jason's answser, I would propose: What about overriding the UIImage's imageNamed: method to have it happen the "-568" suffix to the name of your image? Or add a new method called resolutionAdaptedImageNamed: to the UIImage maybe using a category.
If I have a bit of time in the next days, I will try to post the code for that.
Caution: will not work for images in the Nib files.
If you are using Xcode 5, you can use asset catalog (see usage there Apple's documentation)
Once your asset catalog is created [ UIImage imagedNamed: #"your_image_set" ] will pull right image based on device.
You can also make category for this just make category as below .
UIImage+Retina4.h
#import <UIKit/UIKit.h>
#import <objc/runtime.h>
#interface UIImage (Retina4)
#end
UIImage+Retina4.m
#import "UIImage+Retina4.h"
static Method origImageNamedMethod = nil;
#implementation UIImage (Retina4)
+ (void)initialize {
origImageNamedMethod = class_getClassMethod(self, #selector(imageNamed:));
method_exchangeImplementations(origImageNamedMethod,
class_getClassMethod(self, #selector(retina4ImageNamed:)));
}
+ (UIImage *)retina4ImageNamed:(NSString *)imageName {
// NSLog(#"Loading image named => %#", imageName);
NSMutableString *imageNameMutable = [imageName mutableCopy];
NSRange retinaAtSymbol = [imageName rangeOfString:#"#"];
if (retinaAtSymbol.location != NSNotFound) {
[imageNameMutable insertString:#"-568h" atIndex:retinaAtSymbol.location];
} else {
CGFloat screenHeight = [UIScreen mainScreen].bounds.size.height;
if ([UIScreen mainScreen].scale == 2.f && screenHeight == 568.0f) {
NSRange dot = [imageName rangeOfString:#"."];
if (dot.location != NSNotFound) {
[imageNameMutable insertString:#"-568h#2x" atIndex:dot.location];
} else {
[imageNameMutable appendString:#"-568h#2x"];
}
}
}
NSString *imagePath = [[NSBundle mainBundle] pathForResource:imageNameMutable ofType:#"png"];
if (imagePath) {
return [UIImage retina4ImageNamed:imageNameMutable];
} else {
return [UIImage retina4ImageNamed:imageName];
}
return nil;
}
#end
And you can directly check using import this category as below where you wont to check 568 or normal image
imgvBackground.image=[UIImage imageNamed:#"bkground_bg"];//image name without extantion
Related
i researched so much about that but i cant find anything interesting.. actually i had a project in cocos2d made in ios5 and show images size good either in retina .. when upgraded to ios6 it shows one fourth image sizes.. It shows Retina display ON in CCDirector.
I Think this will helps you.
NSString *iPadtext;
NSString *device = [UIDevice currentDevice].model;
NSLog(#"deive name is %#",device);
Add both images like pause.png and pause-hd.png
if([device isEqualToString:#"iPad"] || [device isEqualToString:#"iPad Simulator"] ){
iPadtext = #"-hd";
}
CCMenuItemImage *pauseMenuItem = [CCMenuItemImage
itemFromNormalImage:[NSString stringWithFormat:#"pause_01%#.png",iPadText] selectedImage:[NSString stringWithFormat:#"pause_01-over%#.png",iPadText]
target:self selector:#selector(PauseButtonTapped:)];
i hope it will help you
I'm kinda puzzeled about image storage in iOS devices for an app i'm making.
My requirement is to load an Image onto a tableViewCell, lets say in the default Image space of a UITableViewCell and hence isnt a background image.
Now The user can either add an Image either via the PhotoDirectory or take an entirely new image.
If a new image is taken, where should that image be stored preferebly? In the default photo directory ? or in the documents folder of the app sandbox?
Because these are image files, I'm afraid that store images within the app bundle can make it pretty big, I'm afraid I dont wana cross the size limit.
Performance wise though... what would be a better option?
I have an app that also does some of the things you describe. My solutions was to create a singleton that I call my imageStore. You can find information about a singleton here
In this imageStore, I store all my "full size" images; however, like you I am concerned about the size of these images, so instead of using them directly, I use thumbnails. What I do is this. For each object that I want to represent in the table, I make sure the object has a UIImage defined that is about thumnail size (64x64 or any size you desire). Then an object is created, I create a thumbnail that I store along with the object. I use this thumbnail instead of the larger images where I can get a way with it, like on a table cell.
I'm not behind my Mac at the moment, but if you want I can post some code later to demonstrate both the singleton and the creation and usage of the thumbnail.
Here is my header file for the ImageStore
#import <Foundation/Foundation.h>
#interface BPImageStore : NSObject {
NSMutableDictionary *dictionary;
}
+ (BPImageStore *)defaultImageStore;
- (void)setImage:(UIImage *)i forKey:(NSString *)s;
- (UIImage *)imageForKey:(NSString *)s;
- (void)deleteImageForKey:(NSString *)s;
#end
Here is the ImageStore.m file - my Singleton
#import "BPImageStore.h"
static BPImageStore *defaultImageStore = nil;
#implementation BPImageStore
+ (id)allocWithZone:(NSZone *)zone {
return [[self defaultImageStore] retain];
}
+ (BPImageStore *)defaultImageStore {
if(!defaultImageStore) {
defaultImageStore = [[super allocWithZone:NULL] init];
}
return defaultImageStore;
}
- (id)init
{
if(defaultImageStore) {
return defaultImageStore;
}
self = [super init];
if (self) {
dictionary = [[NSMutableDictionary alloc] init];
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:#selector(clearCach:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
}
return self;
}
- (void) clearCache:(NSNotification *)note {
[dictionary removeAllObjects];
}
- (oneway void) release {
// no op
}
- (id)retain {
return self;
}
- (NSUInteger)retainCount {
return NSUIntegerMax;
}
- (void)setImage:(UIImage *)i forKey:(NSString *)s {
[dictionary setObject:i forKey:s];
// Create full path for image
NSString *imagePath = pathInDocumentDirectory(s);
// Turn image into JPEG data
NSData *d = UIImageJPEGRepresentation(i, 0.5);
// Write it to full path
[d writeToFile:imagePath atomically:YES];
}
- (UIImage *)imageForKey:(NSString *)s {
// if possible, get it from the dictionary
UIImage *result = [dictionary objectForKey:s];
if(!result) {
// Create UIImage object from file
result = [UIImage imageWithContentsOfFile:pathInDocumentDirectory(s)];
if (result)
[dictionary setObject:result forKey:s];
}
return result;
}
- (void)deleteImageForKey:(NSString *)s {
if(!s) {
return;
}
[dictionary removeObjectForKey:s];
NSString *path = pathInDocumentDirectory(s);
[[NSFileManager defaultManager] removeItemAtPath:path error:NULL];
}
#end
Here is where I use the image store. In my Object "player", I have a UIImage to store the thumbnail and I have an NSString to house a key that I create. Each original image I put into the store has a key. I store the key with my Player. If I ever need the original image, I get by the unique key. It is also worth noting here that I don't even store the original image at full size, I cut it down a bit already. After all in my case, it is a picture of a player and nobody has too look so good as to have a full resolution picture :)
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
NSString *oldKey = [player imageKey];
// did the player already have an image?
if(oldKey) {
// delete the old image
[[BPImageStore defaultImageStore] deleteImageForKey:oldKey];
}
UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
// Create a CFUUID object it knows how to create unique identifier
CFUUIDRef newUniqueID = CFUUIDCreate(kCFAllocatorDefault);
// Create a string from unique identifier
CFStringRef newUniqueIDString = CFUUIDCreateString(kCFAllocatorDefault, newUniqueID);
// Use that unique ID to set our player imageKey
[player setImageKey:(NSString *)newUniqueIDString];
// we used Create in the functions to make objects, we need to release them
CFRelease(newUniqueIDString);
CFRelease(newUniqueID);
//Scale the images down a bit
UIImage *smallImage = [self scaleImage:image toSize:CGSizeMake(160.0,240.0)];
// Store image in the imageStore with this key
[[BPImageStore defaultImageStore] setImage:smallImage
forKey:[player imageKey]];
// Put that image onto the screen in our image view
[playerView setImage:smallImage];
[player setThumbnailDataFromImage:smallImage];
}
Here is an example of going back to get the original image from the imageStore:
// Go get image
NSString *imageKey = [player imageKey];
if (imageKey) {
// Get image for image key from image store
UIImage *imageToDisplay = [[BPImageStore defaultImageStore] imageForKey:imageKey];
[playerView setImage:imageToDisplay];
} else {
[playerView setImage:nil];
}
Finally, here is how I create a thumbnail from the original image:
- (void)setThumbnailDataFromImage:(UIImage *)image {
CGSize origImageSize = [image size];
CGRect newRect;
newRect.origin = CGPointZero;
newRect.size = [[self class] thumbnailSize]; // just give a size you want here instead
// How do we scale the image
float ratio = MAX(newRect.size.width/origImageSize.width, newRect.size.height/origImageSize.height);
// Create a bitmap image context
UIGraphicsBeginImageContext(newRect.size);
// Round the corners
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:newRect cornerRadius:5.0];
[path addClip];
// Into what rectangle shall I composite the image
CGRect projectRect;
projectRect.size.width = ratio * origImageSize.width;
projectRect.size.height = ratio *origImageSize.height;
projectRect.origin.x = (newRect.size.width - projectRect.size.width) / 2.0;
projectRect.origin.y = (newRect.size.height - projectRect.size.height) / 2.0;
// Draw the image on it
[image drawInRect:projectRect];
// Get the image from the image context, retain it as our thumbnail
UIImage *small = UIGraphicsGetImageFromCurrentImageContext();
[self setThumbnail:small];
// Get the image as a PNG data
NSData *data = UIImagePNGRepresentation(small);
[self setThumbnailData:data];
// Cleanup image context resources
UIGraphicsEndImageContext();
}
I am using Three20's TTLauncherView and was wondering whether anyone has had experience loading high resolution images?
http://three20.info/showcase/launcher
I am using the following method to set my TTLauncherItem's:
NSString *imageUrl = [self displayImageUrl:#"http://foo.com/lowres.png" withHighResUrl:#"http://foo.com/hires.png";
TTLauncherItem *launcherItem = [[[TTLauncherItem alloc] initWithTitle:#"Icon1"
image:imageUrl
URL:#"Icon1"
canDelete:NO] autorelease];
This is the method I use to determine whether it's an iOS4.
- (NSString *)displayImageUrl:(NSString *)standardResUrl withHighResUrl:(NSString *)highResUrl {
NSString *imageUrl = nil;
if ([[UIScreen mainScreen] respondsToSelector:#selector(scale)] && [[UIScreen mainScreen] scale] == 2) {
imageUrl = highResUrl;
} else {
imageUrl = standardResUrl;
}
return imageUrl;
}
The problem is that images are actually getting displayed in their full dimensions on an iPhone 4, whereas any iOS device below an iPhone 4 are getting displayed properly. Just wondering whether I would need to make changes to the TTLauncherView library or whether there's an easier way to resolve such an issue.
I accomplished this by adding a new style to my three20 stylesheet based on launcherButtonImage. This is the original...
- (TTStyle*)launcherButtonImage:(UIControlState)state {
TTStyle* style =
[TTBoxStyle styleWithMargin:UIEdgeInsetsMake(-7, 0, 11, 0) next:
[TTShapeStyle styleWithShape:[TTRoundedRectangleShape shapeWithRadius:8] next:
[TTImageStyle styleWithImageURL:nil defaultImage:nil contentMode:UIViewContentModeCenter
size:CGSizeZero next:nil]]];
if (state == UIControlStateHighlighted || state == UIControlStateSelected) {
[style addStyle:
[TTBlendStyle styleWithBlend:kCGBlendModeSourceAtop next:
[TTSolidFillStyle styleWithColor:RGBACOLOR(0,0,0,0.5) next:nil]]];
}
return style;
}
...and this is the updated version...
- (TTStyle*)favoriteLauncherButtonImage:(UIControlState)state {
TTStyle* style =
[TTShapeStyle styleWithShape:[TTRoundedRectangleShape
shapeWithRadius:4.0] next:
[TTBoxStyle styleWithMargin:UIEdgeInsetsMake(0, 0, 0, 0)
padding:UIEdgeInsetsMake(16, 16, 16, 16)
minSize:CGSizeMake(0, 0)
position:TTPositionStatic next:
[TTImageStyle styleWithImageURL:nil defaultImage:nil contentMode:UIViewContentModeScaleAspectFit
size:CGSizeMake(64, 64) next: nil
]]];
if (state == UIControlStateHighlighted || state == UIControlStateSelected) {
[style addStyle:
[TTBlendStyle styleWithBlend:kCGBlendModeSourceAtop next:
[TTSolidFillStyle styleWithColor:RGBACOLOR(0,0,0,0.5) next:nil]]];
}
return style;
}
There's probably stuff in there you don't need like rounded image corners. The operative part is the TTImageStyle directive which locks the image size to 64x64. Hope this helps.
I am using Three20's TTLauncherView
Instead, try using SDWebImage:
https://github.com/rs/SDWebImage
You could just issue two loads on a UIImageView, one for the high and one for the low res image. The low-res should finish first...
I want to get status bar images without UIGetScreenImage() because this method is Private API.
Apple recommend
http://developer.apple.com/iphone/library/qa/qa2010/qa1703.html
as a alternate solution, but this way can't get status bar images.
Would like to know how to get status bar images?
This is impossible without using the Private API.
Referencing this duplicate: Emailing full screen of iPhone app
CGImageRef UIGetScreenImage();
#interface UIImage (ScreenImage)
+ (UIImage *)imageWithScreenContents;
#end
#implementation UIImage (ScreenImage)
+ (UIImage *)imageWithScreenContents
{
CGImageRef cgScreen = UIGetScreenImage();
if (cgScreen) {
UIImage *result = [UIImage imageWithCGImage:cgScreen];
CGImageRelease(cgScreen);
return result;
}
return nil;
}
#end
So I've got a function that really helps when I'm crafting device specific URLS but I'd like to place it in a global header file so any class could use it easily
- (NSString *)deviceType
{
NSString *deviceName = #"iphone";
if([[UIScreen mainScreen] respondsToSelector:#selector(scale)])
{
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad){
deviceName = #"ipad";
}
else {
deviceName = #"iphone4";
}
}
return deviceName;
}
That may or may not be the best way of doing it but I'd like to know how to get that into a global header so I can do something like this
NSString *deviceName = GETDEVICENAME;
#define GETDEVICENAME [whatever deviceType] maybe?
There is an issue with your function though, on 3.2 UIScreen doesn't respond to scale (at least no publicly. I wouldn't rely on that to check for iPad.
With in your project should be a file called %PROJECT%_Prefix.pch.
Any headers you include in that file will be accessible by all files in your project.
Got the answer that worked for me,
In a global header file Globals.h I placed
NSString* deviceType();
in Globals.m I placed a modified function
NSString* deviceType()
{
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad){
return #"ipad";
}
else if([[UIScreen mainScreen] respondsToSelector:#selector(scale)])
{
return #"iphone4";
}
else{
return #"iphone";
}
}