I have an PNG image file foo#2x.png that is 128x128 pixels. My expectation is that when I load it on a retina device the resulting size will be 64x64 points. In fact though I am getting a UIImage* that is 100x100 pts, where the extra points (18pts on each side) are just empty (I confirmed by drawing a border in the containing UIImageView*).
I have tried loading the image via [UIImage imageNamed], [UIImage imageWithData], and [UIImage imageWithData:scale]. They all give back the same image, and I'm confused. Anyone able to explain where this extra space is coming from?
[EDIT] Per John's request,
[UPDATE] It seems this had to do with the simulator caching something from somewhere. Deleting the app from the simulator, doing a clean build, and re-running gives me the size expected. Not clear how this happened, since this isn't a changed or modified image file -- it's totally new and has never existed at 100x100 pts. Open to hearing how this could happen, but don't want to waste anyone's time chasing rabbits.
Answering my own question (see last UPDATE), somewhat bewildered but willing to move on with a healthy suspicion of what the simulator is doing.
Related
Is there an accepted way, or updated way, to more quickly load images into a UIImageView?
My scenario: A collection view, with a large UIImageView. Only 1 cell is displayed at a time. I have implemented NSCache and Prefetching on the collection view already. Performance on scrolling has a pause partway through. The images I am using are "relatively" large, in order to accomodate both an iPad and iPhone layout. For example, images are 1600x1600px, RGB, PNG. (from 2-5MB compressed, ~10MB uncompressed, stored locally in the app)
Once the images are loaded, scrolling back and forth is usually OK then, ~60fps visually. But on first load they are ALWAYS jittery. BUT if I make the images physically smaller, such as 800x800 then they load quickly and I can not see a jitter on scroll. So I am dealing with an image size vs drawing speed issue. Same issue seen on a 5s as on an iPhone X.
The same performance hit happens with [UIImage imageNamed:imageName] or [UIImage imageWithContentsOfFile:imagePath]
I am reading how UIImages are decompressed before actually being drawn, and if the system has to draw a subsampled image, it can significantly affect main thread performance. I've done a little Instruments testing and confirmed that it appear that none of my code is actually slow, the image drawing of a PNG is slow.
Is there a newer way to do something similar to the content in links below, IE draw an image in a CGContext and hope it stays cached?
https://www.cocoanetics.com/2011/10/avoiding-image-decompression-sickness/
- (void)decompressImage:(UIImage *)image
{
UIGraphicsBeginImageContext(CGSizeMake(1, 1));
[image drawAtPoint:CGPointZero];
UIGraphicsEndImageContext();
}
https://gist.github.com/steipete/1144242
this seems like real overkill for me:
https://github.com/path/FastImageCache
I have implemented NSCache and Prefetching on the collection view already.
Good, but
(1) you should not NSCache images
(2) you should downsize the image to the max size needed for display
(3) you should not be doing anything time-consuming in itemForRowAt: (you didn't show yours) — you have only a couple of milliseconds to produce the cell and get out
(4) if you can't provide the image in time, provide a placeholder and get out of itemForRowAt:; you can always reload later when you have the real image
(5) do all time-consuming work off the main thread (includes converting to UIImage and drawing UIImage to downsize it)
(6) measure measure measure! this is why we have Instruments; do not guess where the problem is
I have a very strange bug which appears randomly amongst users. In most cases, the same image loaded into a UIImageView shows perfectly, but occasionally has an artefact line running through it as in the pic attached. We cannot reproduce during testing on either the simulator or device. The image loaded is a simple png:
groupAvatarIV = [[UIImageView alloc] initWithFrame:CGRectMake(horizontalMargin, 5, 70, 70)];
groupAvatarIV.clipsToBounds = YES;
groupAvatarIV.layer.cornerRadius = 70 /2;
groupAvatarIV.image = [UIImage imageNamed:#"avatar"];
[contentV addSubview:groupAvatarIV];
I am really out of ideas how to debug this - any tips would be appreciated please.
It looks like the image contains data for a width greater than itself, so it keeps writing data in an address that becomes the next line down etc... (evidenced by the fact that it starts at the widest part of the circle)
maybe there is something wrong with the params on the image, or it might just be an apple bug...
if it is an apple bug, I would expect it to be with the behavior of clipToBounds
try to collect OS info from the users that experience it... also you could try to re-save the images using a different program, like use ffmpeg to save them as a tiff, then convert back to png (which should be a lossless route), so you know it had to re-interpret it...
Turned out the project which we took over contained multiple image files with the same name, which is what caused the artefacts.
You have mentioned that you have added the imageView in another view as a subview. It seems that the image view is not fit to the superview. You need to check the frame size of both views. Then you need to set the frame of the image view equal to or less than the superview.
I know this is a stupid problem, but this is my first real app that I have to make, I have no one to ask and I looked up this problem and found no other similar problems.
My app crashes on real devices with no exception. I saw in the simulator that uses too much RAM and after a while I got to the conclusion that the pictures I am using are to blame.
The app is structured in this way: it has 8 viewControllers for different things: for example, it starts with one which lets the user select the avatar with which he/she will play and here I have two pictures, next is a viewController which shows the stats for that avatar and here it is another picture and so on. The problem is that each picture uses 40MB of RAM to be displayed and things add up so the app uses more than 300MB of RAM when the user gets to the gameviewCOntroller where the game is. Because of this, on devices like iPAD 2 or iphone 4 it crashes, but not on iphone 5.
I tried to set the images both from "images.xcassets" and from a ".atlas" folder, but the result is exactly the same. The pictures have a dimension of no more than 1500x1999px, they are in png format.
Also, I saw that if the app were to start directly into the gaveViewController it would use 180MB so the other viewController remain in memory or something like that. Should I "clear" them or something similar?
//-------update-------
This is what I got from Instruments:
Memory is a big deal on mobile devices, there is not a clear answer to you question, but I can give you some advices:
If your images are plain colors or have symmetric axes use resizable images. You can just use one line of pixel multiplied by with or height to cover the entire screen using a small amount of memory
Image compression doens't have effects when the image is decompressed. So if you have a png that is 600kb and you are thinking that converting in a 300kb will lower memory usage is only true for "disk space" when an image is decompressed in memory the size is widthXheightXNumber_of_channelXbit_for_channel
resize images: if are loading a 2000px square image into memory and you show it inside an image view of 800 px square, resize before adding it.You will have just a peak while resizing, but later it will use less memory
If you need to use big images, use tiling techniques such as CATiledLayer
If you don't need an image anymore get rid of it. It's ok to have an array of path to images, but not an array of full uncompressed images
Avoid -imageNamed it caches images and even if Apple says that this cache is released under memory pressure, you don't have a lot of control on it and it could be too late to avoid a crash
Those are general advices, it's up to you if they fit your requirements.
You should definitely follow Andrea's advices.
Additionally you should consider setting the image size to exactly what your need is. You're saying that you've tried to set them from xcassets so you have full control over the images you're loading, which is great (compared to downloading an image that you cannot modify).
I highly suggest you read some documentation on using Asset catalog files. This will allow you to have high-resolution image for bigger screens that also have more memory, and smaller ones for older devices, which is what you want here.
Also, note that 1500x1999px is still a very big size for most mobile devices.
More links about screen-size:
https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/MobileHIG/IconMatrix.html
http://www.paintcodeapp.com/news/iphone-6-screens-demystified
My problem is that my application's icon seems to be resized to fit the rounded-corner mask applied when displayed on the home screen.
EDIT: Here's the image:
My image follows the guidelines in these locations (mainly that it is 120x120, and doesn't have pre-rounded corners):
https://developer.apple.com/library/ios/qa/qa1686/_index.html
https://developer.apple.com/library/ios/documentation/iphone/conceptual/iphoneosprogrammingguide/App-RelatedResources/App-RelatedResources.html#//apple_ref/doc/uid/TP40007072-CH6-SW4
I've tried:
1) Using an image catalog
2) Searching for the issue on this site. I looked through the first 5 paginations sorted by newest and can't find anyone who's had the issue...
3) Making sure that the image is specified in the info.plist
4) Checking the troubleshooting app icon issues on the apple developer site.
The icon always ends up drawn with the black edges.
Is there a way to programmatically make sure the mask is applied correctly?
Has someone else encountered the same issue?
It sounds like you might have the wrong DPI set in the icon PNG—if it’s something other than 72 (the screen’s nominal DPI in points), the system may be trying to scale it to match.
It looks like the DPI was correct. The problem was that there was a transparent background layer, wider than the image that Android Studio seemed to have added when it was run through that deployment process. The layer went unnoticed in preview because it doesn't highlight the transparency. Noticed it when I opened it in GIMP.
So it was a silly oversight on my part.
This might not be the proper place to ask this since it seems the issue is with the actual image, but I'm hoping someone here has seen this issue before.
I am loading images from a server. First I take the photo, upload it from the server and then view it in a different part of the application. This is when I saw that the aspect ratio of any image I had just uploaded was way off. See image one below. Images that I had uploaded in the past did not have these issues. The difference is that I had to pull the previous images into photoshop to rotate them.
I got my node.js server to orient them for me but then when I load them up in the UIImageView they are squished and stretched. Viewing them in the browser or on my computer shows them as normal. Out of curiosity I opened one in photoshop, did not manipulate it at all and saved it out. When I uploaded it to my server and viewed it on the iPhone again it looked as it should. See the second image below.
Again all other images load just fine but the ones that did not go through Photoshop come out all wonky.
Any thoughts? Thanks in advance for your help.
EDIT : When viewing the photos in the browser they are also stretched when resized. When I click to view full size and then click again to view the scaled to fit the screen they look fine. Just wanted to throw some more info out there to see if anyone knows what's up.
try this code,
- (UIImage*)imageWithImage:(UIImage*)images
scaledToSize:(CGSize)newSize;
{
UIGraphicsBeginImageContext( newSize );
[images drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
and then set imageview imaeg this way
imageView.image = [self imageWithImage:mi.imageView.image scaledToSize:CGSizeMake(78, 78)];
I'm not sure what the problem is exactly but I found a sort of solution.
First off I tried it from a 4s to make sure it wasn't an issue with my phone and I got the same result. I found out that if I strip the exif data out of the image it seems to work just fine. What I ended up doing is using a package on my server, GraphicsMagic, and running the images through autoOrient. After this is done and saved out to disk the images load just fine in both the browser and on the iPhone. If anyone has any explanation of what would cause that, that would be great.
Thanks!