imageWithSize Flakey with MPMediaItemArtwork in iOS8 - uiimage

In my app, I display album artwork on a button. On an iPhone 5, the button bounds size is 273x269.5. My code to size the artwork has always been very straightforward and nothing has changed.
MPMediaItem *currentItem = [musicPlayer nowPlayingItem];
MPMediaItemArtwork *iTunesArtwork = [currentItem valueForProperty: MPMediaItemPropertyArtwork];
CGSize buttonBounds = self.albumArtworkButton.bounds.size;
UIImage *resizedImage = [iTunesArtwork imageWithSize: CGSizeMake (buttonBounds.width, buttonBounds.height)];
Suddenly with iOS8, the execution of this results in resizedImage = nil. What is really strange is that if I change the last line, the execution of the following line:
UIImage *resizedImage = [iTunesArtwork imageWithSize: CGSizeMake (300, 300)];
results in a valid image (i.e. resizedImage is not nil and the image can be displayed).
Any ideas what might cause this? I haven't changed anything, but the code broke.

I'm seeing this new bug in iOS8 with my apps also. It was only happening for some of the coverart and it depended on what my target size was. it seems the bug has something to do with it can't reduce an image by some factor. For example I have some images from iTunes that are 600x600 and when I try to get an imageWithSize of 100x100 it returns nil while trying to get an imageWithSize of 200x200 works. I have one image that is 200x203 and 100x100 doesn't work, 101x101 doesn't work, but 102x102 will work - I thought maybe the highest resolution you wanted needed to be more than 1/2 of the original dimension to avoid the bug but that didn't turn out to be true based on the 600x600 images working at 200x200. perhaps its the total memory size change or something like that - anyway it's hard to figure out why a bug happens when you don't have their source so I stopped guessing and used this workaround. basically just use the original bounds of the MPMediaItemArtwork object when you request the UIImage via imageWithSize. Then make sure the UIImageView you use with the UIImage has it's contentMode set to display the image properly (UIViewContentModeScaleAspectFill, UIViewContentModeScaleAspectFit, UIViewContentModeScaleToFill).
// display album artwork
MPMediaItemArtwork* artwork = [representativeItem valueForProperty:MPMediaItemPropertyArtwork];
CGRect bounds = [artwork bounds];
UIImage* artworkImage = [artwork imageWithSize:bounds.size];
if (artworkImage)
{
[cell.imageView setImage:artworkImage];
}
else
{
[cell.imageView setImage:[UIImage imageNamed:#"AlbumDefault.png"]];
}

Related

Render a CVPixelBuffer to an NSView (macOS)

I have a CVPixelBuffer that I'm trying to efficiently draw on screen.
The not-efficient way of turning into an NSImage works but is very slow, dropping about 40% of my frames.
Therefore, I've tried rendering it on-screen using CIContext's drawImage:inRect:fromRect. The CIContext was initialized with a NSOpenGLContext who's view was set to my VC's view. When I have a new image, I call the drawImage method which doesn't spit out any errors... but doesn't display anything on screen either (it did log errors when my contexts were not correctly setup).
I've tried to find an example of how this is done on MacOS, but everything seems to be for iOS nowadays.
EDIT:
Here's some of the code I am using. I've left out irrelevant sections
On viewDidLoad I init the GL and CI contexts
NSOpenGLPixelFormatAttribute pixelFormatAttr[] = {
kCGLPFAAllRenderers, 0
};
NSOpenGLPixelFormat *glPixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes: pixelFormatAttr];
NSOpenGLContext *glContext = [[NSOpenGLContext alloc] initWithFormat:glPixelFormat shareContext:nil];
glContext.view = self.view;
self.ciContext = [CIContext contextWithCGLContext:glContext.CGLContextObj pixelFormat:glPixelFormat.CGLPixelFormatObj colorSpace:nil options:nil];
Then, when a new frame is ready, I do:
dispatch_async(dispatch_get_main_queue(), ^{
[vc.ciContext drawImage:ciImage inRect:vc.view.bounds fromRect:ciImage.extent];
vc.isRendering = NO;
});
I am not sure I'm calling draw in the right place, but I can't seem to find out where is this supposed to go.
If the CVPixelBuffer has the kCVPixelBufferIOSurfaceCoreAnimationCompatibilityKey attribute, the backing IOSurface (retrieved via CVPixelBufferGetIOSurface) can be passed directly to the contents property of a CALayer.
This is probably the most efficient way to display a CVPixelBuffer.

iOS8 How to set TabBarItem images

It seems something has changed with iOS8 and now none of my tab bar icons are showing up properly. Most of the time they don't show until the tab is active:
But sometimes they don't show up at all and give me just a big blue box (like whenever I dismiss a view that covered the whole window):
This is what I did pre iOS8:
UITabBarController *tabBarController = (UITabBarController *)self.window.rootViewController;
UITabBar *tabBar = tabBarController.tabBar;
UITabBarItem *tabBarItem1 = [tabBar.items objectAtIndex:0];
[tabBarItem1 setFinishedSelectedImage:[UIImage imageNamed:#"paintbrush-white.png"] withFinishedUnselectedImage:[UIImage imageNamed:#"paintbrush-black.png"]];
tabBarItem1.imageInsets = UIEdgeInsetsMake(6, 0, -6, 0);
tabBarItem1.title = #"";
as mentioned, if you take a look at:
https://developer.apple.com/Library/ios/documentation/UIKit/Reference/UITabBarItem_Class/index.html#//apple_ref/occ/instm/UITabBarItem/setFinishedSelectedImage:withFinishedUnselectedImage:
you will notice that this method is deprecated, try to change:
[tabBarItem1 setFinishedSelectedImage:[UIImage imageNamed:#"paintbrush-white.png"] withFinishedUnselectedImage:[UIImage imageNamed:#"paintbrush-black.png"]];
to:
[tabBarItem1 setImage:[[UIImage imageNamed:#"paintbrush-white.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]];
[tabBarItem1 setSelectedImage:[[UIImage imageNamed:#"paintbrush-black.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]];
You may also have problems with the image size, depends of the size of image when testing in iPhone 5 screen and iPhone 6 screen for #2x images
Did you try setSelectedImage:?
UIImage *image = [UIImage imageNamed:#"img.png"]
[tabItem setSelectedImage:image];
It works on my part.
This method is deprecated in iOS 8:
Use initWithTitle:image:selectedImage: or the image and selectedImage properties along with UIImageRenderingModeAlwaysOriginal

Xcode 5, why isn't the image resizing?

Hello I am trying to resize a UIImage, but even though I'm not getting any errors it is not working.
hers the code of .h file
IBOutlet UIImageView *Fish;
heres the code of .m file
Fish.frame = CGRectMake(0, 0, 300, 293);
What am I doing wrong?
Thanks for any help
The image is probably not resizing because you are just resizing the image view. Make sure in your storyboard that you make the image view (Fish), have the move ScaleToFill. I can't do screenshot due to reputation ( sorry :( )
Alternately, if your goal is not to resize the image view but to resize the image it is holding, you can do this:
UIImage *image = Fish.image;
UIImage *image = YourImageView.image;
UIImage *tempImage = nil;
CGSize targetSize = CGSizeMake(80,60);
UIGraphicsBeginImageContext(targetSize);
CGRect thumbnailRect = CGRectMake(0, 0, 0, 0);
thumbnailRect.origin = CGPointMake(0.0,0.0);
thumbnailRect.size.width = targetSize.width;
thumbnailRect.size.height = targetSize.height;
[image drawInRect:thumbnailRect];
tempImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
YourImageView.image = tempImage;
and you would set thumbnailRect to whatever size you want.
Hope this helps! Please search Nerdy Lime on the app store to find all of my apps! Thanks!
I bet your outlet is not hooked up. In your "viewDidLoad" method, try doing this:
if(Fish)
{
Fish.frame = CGRectMake(0, 0, 300, 293);
} else {
NSLog(#"Fish is null; why did I forget to connect the outlet in my storyboard or xib?");
}
And this isn't the best way to resize your UIImageView. If you're using regular springs & struts, you can grow an outlet by clicking the springs & struts to grow based on the superview's size, e.g.:
And if you're doing AutoLayout, there's a different thing you can do (basically pin your view to all four sides of the superview).
Here is how I do it:
1) select the outlet / object you want to add constraints to (in your case, it'll be the fish image view)
2) see the segmented control at the bottom of the Interface Builder window? Click on the second one and you'll see a popover view open up with a list of possible constraints to add.
3) In my example, I'm adding constraints in my ImageView to always be 10 pixels from each edge of the superview (note the four "10"s and solid red lines meaning I'm adding four constraints).
AutoLayout is a pain to get accustomed to (and I'm still learning it myself), but I suspect that once one gets the hang of it, it'll be a powerful new tool especially as Apple brings in additional iOS screen sizes in the very near future.

IKImageBrowserView with background and wantsLayer

In my app I use IKImageBrowserView with background. If wantsLayer NO - all fine and IKImageBrowserView look like nice. But if I enabled wantsLayer (in parent view) the background in IKImageBrowserView is corrupt. (Sorry English is not my native language and I can't find the correct word).
If I understand correctly, problem in this fragment. But I can't see where.
NSRect visibleRect = [owner visibleRect];
NSRect bounds = [owner bounds];
CGImageRef image = NULL;
NSString *path = [[NSBundle mainBundle] pathForResource:[#"metal_background.tif" stringByDeletingPathExtension] ofType:[#"metal_background.tif" pathExtension]];
if (!path) {
return;
}
CGImageSourceRef imageSource = CGImageSourceCreateWithURL((__bridge CFURLRef)[NSURL fileURLWithPath:path], NULL);
if (!imageSource) {
return;
}
image = CGImageSourceCreateImageAtIndex(imageSource, 0, NULL);
if (!image) {
CFRelease(imageSource);
return;
}
float width = (float) CGImageGetWidth(image);
float height = (float) CGImageGetHeight(image);
//compute coordinates to fill the view
float left, top, right, bottom;
top = bounds.size.height - NSMaxY(visibleRect);
top = fmod(top, height);
top = height - top;
right = NSMaxX(visibleRect);
bottom = -height;
// tile the image and take in account the offset to 'emulate' a scrolling background
for (top = visibleRect.size.height-top; top>bottom; top -= height){
for(left=0; left<right; left+=width){
CGContextDrawImage(context, CGRectMake(left, top, width, height), image);
}
}
CFRelease(imageSource);
CFRelease(image);
Image with problem
Image without problem
Thanks
I tried using IKImageView a few weeks ago and ran in to a number if problems. It's a nice class but it doesn't seem to have been updated in a long time. I doesn't support retina screen and, as you point out goes crazy when you add a layer.
I wanted to do some custom drawing with CALayer over the top of an image. The first thing I tried was to add a layer to the image view, which gave me problems. The solution I went for want to add a custom NSView subview to the image view, add auto layout constraints so that it always the same size, then add a layer hosting view to the subview. This worked fine, so move your drawing code to a custom subview and it should work.
IKImageView
LayerHostingView (<--- add CALayer here)
I ran in to this distorted background image problem as well and it turned out to be that I had set up the CALayer for the background incorrectly. I suspect that you are misunderstanding the cause to be setting wantsLayer to false because when that is set the layer does not immediately redraw new layers that you set.
I reached this conclusion as if I set up the layer correctly, then set wantsLayer false immediately before setting a bad CALayer in the next line of code I see the correct, undistorted image first and only when I scroll (and it redraws) do I see the buggy effects in your screenshot. However if I set wantsLayer true at the same point in code I see the buggy graphics immediately when the browser loads, without having to redraw first.
You can move the wantsLayer false statement further down your code to find the line that's breaking it, it'll be where the layer is reset/updated somewhere.

iOS Colorwithpattern - using a custom iPhone5 image

For my app's loading screen and splash screen, I used up with two different methods to display my iPhone 3, iPhone 4 and iPhone 5 images appropriately.
For the loading screen, simply adding -568h#2x to your image is enough to support iPhone5.
For the splashscreen, I used a series of (if height == ) cases to check the height of the UIScreen's bounds and sourced the appropriate image to the image view. It was apparent to me here that the -568h isn't universally recognized as an iPhone 5 image. It is only applicable to the loading screen.
Now, in my AppDelegate, I'm setting a the background image. All my subviews have a transparent background, so they are supposed to show through to the background image. However, I am having the most trouble setting up the background image here.
Simply passing in the "Background.png" Adding the -568h#2x to the end of the filename does not work. It will do the non-retina and the 3.5'' retina display, but will not pick up for the 4'' display.
ie:
self.window.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"Background.png"]];
If I use the above snippet of code, the iPhone4 picture is used instead of the iPhone5 picture and this is not what I want.
I moved onto trying to do the same thing as I did with the splashscreen. I had a bunch of if cases:
CGFloat height = [UIScreen mainScreen].currentMode.size.height;
if ( height == 1136 )
{
//Choose image here
}
else if (height == 960)
{
//Choose image here
}
else if (height == 480)
{
//Choose image here
}
self.window.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:chosenImage]];
But the colorWithPatternImage function thinks that the chosenImage goes by 1 point = 1 pixel. So I end up with a non-retina picture attempting to fit onto the iPhone 5 screen. What exaclty does it look like? Looks like only the top left quadrant of the image I wanted is displayed over the entire iPhone 5 screen. It looks like no retina scaling was applied.
I need the iPhone to recognize that I have a retina-friendly iPhone 5 picture to be used as the background. How do I do this?
I found this code here, perhaps it helps you:
UIImage *tmpImage = [UIImage imageNamed:#"background-568h#2x.png"];
UIImage *backgroundImage = [UIImage imageWithCGImage:[tmpImage CGImage]
scale:2.0
orientation:UIImageOrientationUp];
self.window.backgroundColor = [UIColor colorWithPatternImage:backgroundImage];

Resources