OSX NSFont differs from the exact same font in Photoshop - macos

I've set my font in Photoshop to be Helvetica Neue Regular with 22pt - without any additional customizations.
Now I need the exact same result in my OSX application which seems to be quite hard to achieve.
I modify the font of my NSTextField using
self.label.font = [NSFont fontWithName:#"HelveticaNeue" size:22];
I've created a comparison of HelveticaNeue(regular) and HelveticaNeue-Medium, Photoshop and OSX.
It seems like the OSX part is always a bit more bold and has a slightly reduced letter spacing.
It might be possible to play around a while and adjust the font on OSX using NSAttribuedString until it matches to Photoshop font, but is this really necessary? Shouldn't the font be exactly the same?

There are many ways to render fonts. Apparently, Photoshop has its own font-rendering engine and it differs from what NSTextField is doing by default.
If you zoom your image up in size (in a way that doesn't attempt to smooth the result), you'll see that the Photoshop rendering uses gray-scale anti-aliasing while the OS X rendering uses sub-pixel anti-aliasing. The OS X rendering has color fringes. When rendered at normal sizes, those colors end up lighting the different RGB elements in the LCD screen. Rather than looking colored, it just looks like changing in brightness. Basically, sub-pixel anti-aliasing uses the layout of the color elements within LCD pixels to increase the resolution at which it can render.
I also suspect that the OS X rendering engine is using sub-pixel glyph positioning. That allows for the sizing and spacing of glyphs to more closely follow what the font prescribes, making smaller compromises when being rendered to a grid of pixels. For example, look at the first line (Helvetica Neue 22pt: Photoshop). The spacing between the "H" and the "e" and between the "l" and the "v" looks wrong to me. OS X looks better to my eye.
If you render text yourself, you can turn off sub-pixel anti-aliasing using CGContextSetShouldSubpixelQuantizeFonts() and turn off sub-pixel positioning using CGContextSetShouldSubpixelPositionFonts(). (The documentation suggests that turning off sub-pixel positioning also turns off sub-pixel anti-aliasing, although I'm not sure why that would necessarily follow.) See if that produces results more like what Photoshop is giving you.
By the way, it's probably possible to adjust how Photoshop renders the font, too. Just because two things are ostensibly rendering the same font, doesn't mean they will produce identical pixels.

Related

Achieve pixel perfect on Canvas?

I want to make exact 1-pixel thick line without distortions. (means not appeared as 2-pixel lines or 1.5-pixel lines, etc) Because it seems like the Canvas just can't stand Pixel Perfect at times.
It is also depends on CanvasScaler setting, make sure that screen/canvas output is exactly at scale 1x.
Confirm that canvas final scale is all 1x
Also confirm that your displaying game window has 1x scale so that 1 pixel show up nicely too!
(View full unscaled image in another window if sprite in above image appear jagged)
For canvas scaler setting, if you use it in other mode such as "Scale with screen size", and its reference resolution did not match current game window, it will result in non 1x scaling.
If scale is non uniform, jagged or blurry line will start to appear on canvas.
Notice the middle sword sprite.
Canvas' pixel perfect tick box helped nothing so far.
Actually, sorry. Canvases try to respect screen pixels when scaling with PixelPerfect set to true.
The solution was pretty easy - just setting PixelPerfect to false. I got so used to set it to true (because of the UI style I was going for before) that I didn't even consider turning it off. I guess that's mainly due to its name - Pixel Perfect.
xD

NSColor colorWithPatternImage: and scaling (NSAffineTransform)

So the AppleDocs state that:
The image to use as the pattern for the color object. The image is tiled starting at the bottom of the window. The image is not scaled.
(NSColor Class Reference)
Well, except the pattern sort of does scale..
At least when drawing into a graphics context that is scaled up/down using CAAffineTransform.
However, the pattern is scaled by some lesser degree than the actual graphics, e.g. when drawing a filled NSBezierPath object and scaling the context up/down the pattern is just slightly scaled up/down, not by the same factor.
This is observed on OS X 10.6 - any ideas if that's a bug or some documented behaviour?
Ideally we'd like to use the same pattern scale factor no matter how big or small the scaled graphic (rect, bezierpath, ..) is.

NSImage Overlay/Mask Gradient like iOS

I'm looking to replicate with Cocoa/Core Graphics the process which seems to occur on iOS when setting an image for a UITabBarItem. When the tab bar item is selected, the image is overlayed with a gradient.
For example,
becomes...
I'm unsure exactly what I should be doing to achieve this effect. It seems like the image is masking the gradient. Any pointers in the right direction (or code!) would be much appreciated.
You can use a monochrome CGImage with alpha channel (like most iPhone tool-/tabbar icons) as a mask. Basically, you'd use CGContextClipToMask with your monochrome image. Then you'd draw the gradient which is then clipped to the mask image. You might also want to have a look at the code of UMEKit, which implements this effect on Mac OS X (haven't looked at how exactly they do it, there are probably several ways).

Using Win32 TextOut to draw text at an angle

I'm using GDI to draw text onto a device context, and I noticed that the kerning or character placement is different if the angle is exactly 0, 90, 180, or 270. As soon as I increase the angle by 1, the character placement differs noticeably.
Rather than creating an HFONT with the angle, I am using ModifyWorldTransform to transform the device context's world coordinates, and then I use TextOut to draw the text onto the device context.
I think that GDI is using font hints or some other special technique when the text is being drawn at exact multiples of 90 degrees, but not for any other angle.
Is there a way to disable this hinting, so that text rendered at 0 degrees does not differ significantly from text rendered at 1 degree?
Here's an example of what I mean (Monotype Corsiva font):
0 degrees:
1 degree:
For some fonts, such as Arial or Tahoma, it is not as noticeable, but I would like to get rid of the difference entirely, even if it means the text is not rendered as best it can.
I think this is due to anti-aliasing rather than font hints. You could try the following:
Disable (font) AA, but this will not yield acceptable results.
Create font handles for every possible angle and see if the problem persists. I assume it doesn't, but it's not a pretty solution.
Render the text to a bitmap (e.g. using CreateCompatibleBitmap() ) render the text to it and then render the rotated bitmap. This depends on how often you need different rotations / different text.
Play with fdwOutputPrecision and fdwQuality in CreateFont(). This could be the easiest solution, but you'd have to experiment a little bit I guess.
hth

How does one reproduce the inset text style when drawing text with Mac OS X Cocoa?

I'm talking about the groove style of the text on focussed title bars, or safari's bookmarks bar for example. Is there an easy way to reproduce this style when using:
[string drawAtPoint:... withAttributes:...];
If you want it to look perfect, you'll need to draw the text twice.
As you can see when zooming in on labels below toolbar items in any app, or for instance the bookmarks bar in Safari (Control+scroll up, control+option+\ to toggle smoothing of the zoomed in image), the text is rendered with sub-pixel anti-aliasing, at least when "Font smoothing style:" in the "Appearance" system preferences is set to medium, which it will be by default on Macs with a built-in or external Apple flat-panel display.
NSShadow can not be used with sub-pixel anti-aliasing, so if you simply set an NSShadowAttributeName in the attributes dictionary you're drawing your string with, you will notice sub-pixel anti-aliasing is MIA when you zoom in on your rendered text.  Due to the way NSShadow is designed, no matter what color you set your NSShadow instance to —even if it is opaque— it will always be drawn with an alpha channel, making sub-pixel antialiasing impossible.
The solution is really very simple:
Draw your text once with a white color with some transparancy,
Then draw it once more on top of that, a pixel higher in a shade of grey of your liking with no transparancy.
Your 'shadow' will draw without sub-pixel antialiasing, but the actual text on top op of it will draw with it, giving you the exact same effect as standard Cocoa toolbar button item labels, or items in the Safari bookmarks bar.
EDIT: It seems that Safari's bookmarks bar items draw their 'shadows' with sub-pixel accuracy as well, so the way they did it is probably by choosing an opaque shade of gray for the white 'shadow' text as well; drawback of that approach: you are tying your drawing code to only work well on a particular background color, e.g. if your elements will be used on a blue background, you'll want to set that color to a light shade of blue, to appear like it's semi-transparent white.
Draw it with an un-shadow below it. Use a shadow with color white, opacity 50% or so, blur 0, offset 1 pt down.
A simple way to do this is to simply draw the text twice. The first time, you draw it 1 pt lower, in white, at 50% opacity. The second time, you draw it in the desired position, in the desired color, at the desired (probably 100%) opacity.

Resources