How to fix blurry images on NSButton in cocoa application? - swift

I have a couple of NSButtons which act like player controls (play, pause etc.)
When I assign image to them, that image looks blurry.
let playPauseButton: NSButton = {
let btn = NSButton(frame: .zero)
let image = NSImage(named: "pauseIcon")
btn.imageScaling = NSImageScaling.scaleNone
btn.image = image
btn.setAccessibilityLabel("Pause")
btn.isBordered = false
return btn
}()
The image can be viewed on:
https://www.dropbox.com/s/38tvh49ikc2m4x7/Play.pdf?dl=0
This image is .pdf, but I tried .png with 1x,2x and 3x, and it still looked blurry.
I also checked this question:
Images in NSButton and NSImageView Blurred
But it did not help me either.

The solution was very simple.
Open the asset catalog.
Select all your assets that are blurry.
Open the attribute inspector by pressing: command + option + 4.
Check the box that says "Preserve vector data".
Under that checkbox, look for the "Scale" and set it to "Single scale"
Please note that this only works if your designer exported icons as a PDF file. Also, it wont work if you just convert .png or .jpg to .pdf, the actual vector image must be exported to .pdf.

Here are a number of to try that have fixed blurry edges for me in the past.
Assuming you're running in Mojave and/or using layer backed views, be sure that the NSButton draws its own background color ( setDrawsBackground YES ). Otherwise what can happen with CoreAnimation CALayer is that the blending operation of the NSImage background alpha is substandard/wrong.
This shouldn't apply to an NSImage, but maybe its worth a shot: http://stackoverflow.com/questions/5722085/nsbezierpath-rounded-rectangle-has-bad-corners
[nsImage setScalesWhenResized:NO];
try different NSCompositingOperation NSCompositeCopy vs. NSCompositeSourceOver

Related

Apple Watch Complication Template - Modular small image multicolor

Hello,
I'm trying to create a complication for Apple Watch, in the modularSmall family, using a CLKComplicationTemplateModularSmallSimpleImage. I want the image to be displayed as a multicolor image when the tint is set to "multicolor" (just like the calculator's complication). My issue is that it is always displayed as a white image, and never as a multicolor image. I tried to set the tintColor of both the image provider and the template to .none and other various values, but I can't get my full color image when scrolling trough the templates... My code is as follow :
case .modularSmall:
let imageProvider = CLKImageProvider(onePieceImage: UIImage(named: "Complication/Modular")!)
let template = CLKComplicationTemplateModularSmallSimpleImage(imageProvider: imageProvider)
handler(template)
Any idea to help ?

Videos Appearing as Black Boxes in UIImage Snapshots of WKWebView

I am captruing the content of WKWebView into a UIImage via its CALayer by using the following extenstion to UIImage:
extension UIImage {
class func imageFromLayer(layer: CALayer) -> UIImage {
UIGraphicsBeginImageContextWithOptions(layer.bounds.size, layer.isOpaque, 0.0)
layer.render(in: UIGraphicsGetCurrentContext()!)
let img = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return img!
}
}
When I render the captured image to a UIImageView, I see everything from the web view in the image view; everything, except videos, whose content instead appears as a black box. I encounter the same problem if I use WKWebView's takeSnapshot function or the drawHierarchy function of the UIView class to capture UIImage of the web view. Does anyone know why videos are displayed as black boxes and how one can fix this?
Update 1: Additionally, all GIFs in Google Images are frozen until clicked. A GIF can be unfrozen by clicking on it, at which point it gets resized to take up the whole screen and starts looping.
Update 2: I have read that the recording software OBS sometimes experiences the same problem with capturing videos when the browser that it is capturing uses hardware acceleration. I also read that WKWebView uses hardware acceleration. Is there a way to disable hardware acceleration in WKWebView to try this out? Alternatively, does UIWebView use hardware acceleration?
Update 3: There is another post that reports a similar issue. The poster reports that all GPU rendered content appears black in his screenshots and he believes that hardware acceleration is causing the issue.
Update 4: By using Xcode's "Quick Look" feature I have observed that the layer that is passed to imageFromLayer does not contain the videos (i.e. videos are already represents as black boxes in the passed in layer). This makes me think that WKWebView does not render videos to the same layer as it renders its other content. It also makes me think that if I could access this hypothetical video layer I would be able to combine the two snapshots to form a snapshot of the entire web view.
Update 5: I tried modifying my imageFromLayer function to take a UIView instead of a CALayer so that I could pass WKWebView into it directly. The modified version is shown below, but it did not solve the issue of videos not being displayed. Nevertheless, through the use of Xcode's "Quick Look" feature I was able to observe that the videos are already missing in the UIView of the passed in WKWebView object.
class func createImage(view: UIView) -> UIImage {
UIGraphicsBeginImageContextWithOptions(view.frame.size, view.isOpaque, 0.0)
view.drawHierarchy(in: view.bounds, afterScreenUpdates: true)
let rasterizedView = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return rasterizedView
}
Update 6: Trying to capture the web view via the UIWindow that contains it also results in videos not being captured. I used the below code (note that keyWindow is deprecated) and Xcode's Quick Look feature to test this idea.
let window = UIApplication.shared.keyWindow
let windowLayer = window!.layer

Corrupt image is displayed by image view when using an atlas texture & calling its cgImage() function

As soon as I updated my iPhone XS Max to 13.2.2 & macOS Catalina to 10.15.1 I returned working on my project & ran it onto my device. Immediately I noticed every UIImageView that was displaying a UIImage created from an SKTexture.cgImage() was rendering something that literally looked like the missingno from Pokemon Red.
Those same atlas textures render fine inside SKSpriteNode's.
Log debugging returns the UIImage memory as uiimage anonymous
The horizontal white & blue lines is a single background image that has nothing to do with anything. There's a second, smaller image view on top & it's the one rendering the missingno/corrupt image with the texture cgImage() call.
My code is by the book standard for this:
let image = UIImage(cgImage: SKTextureAtlas(named: char.atlasName).textureNamed(char.imageNames.first!).cgImage()
self.imageView.image = image
self.imageView.layer.magnificationFilter = .nearest
My only guess is the latest update did this. I literally did nothing else after updating my system. Just opened the project & ran it. Any ideas if this can be fixed?
Yes, the standard derived data deletion has been tried.
Xcode -> Product -> Clean Build Folder as well
Mac & iPhone have been restarted
I don't know what else I can do but pray

UITabBarItem images just appear as a grey block

I have created .png icons 20 x 20 and when I set the image property in the nib they just appear grey blocks.
Any ideas?
UPDATE: Here is one of the icons!
The standard tabbar icons in iOS are rendered solely from the alpha channel. Colors are ignored completely. Instead of colors you can use different alpha values that lead to a different shade of gray (or blue if selected)
Make the background of your icons transparent.
Download these attached images and pass them to your designer and ask him to just create images like these (when you open them in PS you'll know the difference)
This happened to me in iOS 5, I got around it by setting UIImage Outlet property in the Xib to 'Custom' and then set the label programmtically so : imageOne = [UIImage imageNames#"Dog.png"];
Try saving the file as png interlaced. In photoshop at least it gives you an option of interlaced or normal.

Retina images from server display incorrectly in table cells

I have a table where the cells' image views are being populated by images that have been previously pulled down off a server. So:
[[cell imageView] setImage:[[[UIImage alloc] initWithContentsOfFile:filePath] autorelease]];
Where "filePath" is the location of these images. Working beautifully, until I decided to be clever and add retina display images to my server. These images (double-sized, obviously) are being displayed, but are shrunk. I had labelled them image#2x.png, hoping that the iPhone would just know what to do with them, but obviously that doesn't work in this context.
I've looked at the discussions, and am guessing I need to do something with the contentsScale of the cell's imageView, like matching it to the screen scale, but I'm not sure exactly how to do this. Any help appreciated.
From server you cannot download automatically retina images.
You need a control like
if (iphone == 4) image=img#2x.png
else image=img.png
to get correct images.
You would need to set the scale factor of the image correctly. Please check the scale property in UIImage
If you load an image from a file whose
name includes the #2x modifier, the
scale is set to 2.0. If the filename
does not include the modifier but is
in the PNG or JPEG format and has an
associated DPI value, a corresponding
scale factor is computed and reflected
in this property. You can also specify
an explicit scale factor when
initializing an image from a Core
Graphics image. All other images are
assumed to have a scale factor of 1.0.
So you can read your image as above, get the CGImage from it and create a new UIImage using + (UIImage *)imageWithCGImage:(CGImageRef)imageRef scale:(CGFloat)scale orientation:(UIImageOrientation)orientation.
A nicer way could be to check the DPI of your retina image and make it 144dpi with a graphics program. According to the scale property documentation this might work, too.