Objective-C - CTFont change font style?
Asked Answered
D

1

1

I have a CTFont that contains a font style, and sumbolic traits.

I want to create a new font with a new style that inherits the symbolic traits of the first font. How can I achieve this?

CTFontRef newFontWithoutTraits = CTFontCreateWithName((CFString)newFontName, CTFontGetSize(font), NULL);
CTFontRef newFont = CTFontCreateCopyWithSymbolicTraits(newFontWithoutTraits, CTFontGetSize(font), NULL, 0, CTFontGetSymbolicTraits(font));

the new font is null here I don't know what should I pass to the 4th parameter in CTFontCreateCopyWithSymbolicTraits.

Deedeeann answered 20/9, 2011 at 21:52 Comment(0)
W
9

I do this line of code to generate a bold font from non-bold font:

CTFontRef newFont = CTFontCreateCopyWithSymbolicTraits(currentFont, 0.0, NULL, (wantBold?kCTFontBoldTrait:0), kCTFontBoldTrait);
  • currentFont is the CTFontRef I want to add symbolic traits to
  • wantBold is a boolean to tell if I want to add or remove the bold trait to the font
  • kCTFontBoldTrait is the symbolic trait I want to modify on the font.

The 4th parameter is the value you want to apply. The 5th is the mask to select the symbolic trait.


You may thing of it as bitmask to apply to the symbolic trait, where the 4th parameter of CTFontCreateCopyWithSymbolicTraits is the value and the 5th parameter is the mask:

  • If you want to set the symtrait and add it to the font, iOS will probably apply sthg like newTrait = oldTrait | (value&mask), setting the bit corresponding to mask to the value of value.
  • If you want to unset the symtrait and remove it from the font, you use the value of 0 as the 4th parameter and iOS will probably apply sthg like newTrait = oldTrait & ~mask to unset the bit.

  • But if you need to, you can also set and unset multiple bits (thus multiple symbolic traits) at once, using the right value that have 1 on bits to set and 0 on bits to unset (or to ignore), and and using the right mask that have 1 on bits that needs to be modified and 0 on bits that don't need to be changed.


[EDIT2]

I finally managed to find the solution for your specific case: you need to get the symtraits mask of your font as you already do… and bitwise-or it with the symtraits of your newFontWithoutTraits font.

This is because newFontWithoutTraits actually do have default symtraits (contrary to what I thought, it has a non-zero CTFontSymbolicTraits value) as the symtraits value also contains info for the font class and such things (so even a non-bold, non-italic font can have a non-zero symtraits value, log the hex value of the symtraits of your font to understand better).

So this is the code you need:

CTFontRef font = CTFontCreateWithName((CFStringRef)@"Courier Bold", 12, NULL);
CGFloat fontSize = CTFontGetSize(font);
CTFontSymbolicTraits fontTraits = CTFontGetSymbolicTraits(font);
CTFontRef newFontWithoutTraits = CTFontCreateWithName((CFStringRef)@"Arial", fontSize, NULL);
fontTraits |= CTFontGetSymbolicTraits(newFontWithoutTraits);
CTFontRef newFont = CTFontCreateCopyWithSymbolicTraits(newFontWithoutTraits, fontSize, NULL, fontTraits, fontTraits);

// Check the results (yes, this NSLog create leaks as I don't release the CFStrings, but this is just for debugging)
NSLog(@"font:%@, newFontWithoutTraits:%@, newFont:%@", CTFontCopyFullName(font), CTFontCopyFullName(newFontWithoutTraits), CTFontCopyFullName(newFont));

// Clear memory (CoreFoundation "Create Rule", objects needs to be CFRelease'd)
CFRelease(newFont);
CFRelease(newFontWithoutTraits);
CFRelease(font);
Winzler answered 20/9, 2011 at 22:1 Comment(9)
this doesn't work for me . I don't know whether I want bold italic or etc>? It should copy it from the old font over. I need a way to get this information from the previous fontDeedeeann
Read my additional info (I've just edited my answer): I explain in details how it works. You don't need to retrieve the previous symbolic traits of your font, CTFontCreateCopyWithSymbolicTraits already copy the font you're passing as the 1st parameter, with its symbolic traits too, and will then modify only the one that are masked by the 5th parameter (bit masking).Winzler
So as explained in the last point of my EDIT, if you ever need to copy the symbolic traits from another font different from the one you are creating a copy from, just pass the symtraits of the font you want to copy traits from in the 4th param, and use all-1's mask as 5th parameter to tell iOS to apply the values for all the symtraits: CTFontRef newFont = CTFontCreateCopyWithSymbolicTraits(newFontWithoutTraits, CTFontGetSize(font), NULL, CTFontGetSymbolicTraits(font), ~0); (~0 is the bitwise negation of 0=0x000000 so it is equivalent to all-1's value 0xFFFFFFFF)Winzler
It returns null as newFont. I check and font, and newFontWithoutTraits both existDeedeeann
Are you sure that the font with the traits you are asking exists on iOS? (added another EDIT about this too). See here for a list of CoreText fonts available on iOS, not all of them have all variants available.Winzler
Here is what I just tested, and no CTFontRef is null here. CTFontRef font = CTFontCreateWithName((CFStringRef)@"Arial Bold", 12, NULL); CGFloat fontSize = CTFontGetSize(font); CTFontSymbolicTraits fontTraits = CTFontGetSymbolicTraits(font); CTFontRef newFontWithoutTraits = CTFontCreateWithName((CFStringRef)@"Arial", fontSize, NULL); CTFontRef newFont = CTFontCreateCopyWithSymbolicTraits(newFontWithoutTraits, fontSize, NULL, fontTraits, ~0);. And if I then check using an CTFontCopyFullName(newFont) it returns "Arial Bold".Winzler
I just realized that this is not a so good idea to use a mask with all bits set to 1 as the CTFontSymbolicTraits type also use its 4 MSB for the font class and not the symtraits. (Seen in doc: "CTFontSymbolicTraits symbolically describes stylistic aspects of a font. The upper 16 bits is used to describe appearance of the font whereas the lower 16 bits for typeface.") so you may try with a mask (5th parameter) of 0xFFFF instead of ~0?Winzler
OK I found the solution (tested and approved: I create plain "Arial" font (newFontWithoutSymtraits) and apply the symtraits of previously created font "Courier Bold" (namely I aply the "bold" symtrait) and ends up with "Arial Bold" :) See my (once again) edited answer!Winzler
Thanks a lot, I appreciate the time you spent on this. I'll give this a try tomorrow morning and I'll respond backDeedeeann

© 2022 - 2024 — McMap. All rights reserved.