さまざまな手法を使用して、MacOS X/iOS でキャラクターのバウンディング ボックスを取得しようとしています。私は今、すべての試みを提示しています。「Ä」などの発音区別記号のサイズを取得したい場合、これまでコードは失敗していました。
使用するCTFontGetBoundingRectsForGlyphs
-(void) resizeLayer1:(CATextLayer *)l toString:(NSString *)string
{
// need to set CGFont explicitly to convert font property to a CGFontRef
CGFontRef layerFont = CGFontCreateWithFontName((CFStringRef)@"Helvetica");
l.font = layerFont;
string = l.string;
NSUInteger len = [string length];
// get characters from NSString
UniChar *characters = (UniChar *)malloc(sizeof(UniChar)*len);
CFStringGetCharacters((__bridge CFStringRef)l.string, CFRangeMake(0, [l.string length]), characters);
// Get CTFontRef from CGFontRef
CTFontRef coreTextFont = CTFontCreateWithGraphicsFont(layerFont, l.fontSize, NULL, NULL);
// allocate glyphs and bounding box arrays for holding the result
// assuming that each character is only one glyph, which is wrong
CGGlyph *glyphs = (CGGlyph *)malloc(sizeof(CGGlyph)*len);
CTFontGetGlyphsForCharacters(coreTextFont, characters, glyphs, len);
// get bounding boxes for glyphs
CGRect *bb = (CGRect *)malloc(sizeof(CGRect)*len);
CTFontGetBoundingRectsForGlyphs(coreTextFont, kCTFontDefaultOrientation, glyphs, bb, len);
CFRelease(coreTextFont);
l.position = CGPointMake(200.f, 100.f);
l.bounds = bb[0];
l.backgroundColor = CGColorCreateGenericRGB(0.f, .5f, .9f, 1.f);
free(characters);
free(glyphs);
free(bb);
}
結果ある程度は機能しますが、グリフが CATextLayer によってレンダリングされるため、パディングが発生します
使用するCTFramesetterSuggestFrameSizeWithConstraints
-(void) resizeLayer2:(CATextLayer *)l toString:(NSString *)string
{
// need to set CGFont explicitly to convert font property to a CGFontRef
CGFontRef layerFont = CGFontCreateWithFontName((CFStringRef)@"Helvetica");
l.font = layerFont;
string = l.string;
NSUInteger len = [string length];
// get characters from NSString
UniChar *characters = (UniChar *)malloc(sizeof(UniChar)*len);
CFStringGetCharacters((__bridge CFStringRef)l.string, CFRangeMake(0, [l.string length]), characters);
// Get CTFontRef from CGFontRef
CTFontRef coreTextFont = CTFontCreateWithGraphicsFont(layerFont, l.fontSize, NULL, NULL);
CFMutableAttributedStringRef attrStr = CFAttributedStringCreateMutable(kCFAllocatorDefault, 0);
CFAttributedStringReplaceString(attrStr, CFRangeMake(0, 0), (__bridge CFStringRef)string);
CTTextAlignment alignment = kCTJustifiedTextAlignment;
CTParagraphStyleSetting _settings[] = { {kCTParagraphStyleSpecifierAlignment, sizeof(alignment), &alignment} };
CTParagraphStyleRef paragraphStyle = CTParagraphStyleCreate(_settings, sizeof(_settings) / sizeof(_settings[0]));
CFAttributedStringSetAttribute(attrStr, CFRangeMake(0, CFAttributedStringGetLength(attrStr)), kCTParagraphStyleAttributeName, paragraphStyle);
CFAttributedStringSetAttribute(attrStr, CFRangeMake(0, CFAttributedStringGetLength(attrStr)), kCTFontAttributeName, coreTextFont);
CFRelease(paragraphStyle);
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(attrStr);
CFRelease(attrStr);
CFRange range;
CGFloat maxWidth = CGFLOAT_MAX;
CGFloat maxHeight = 10000.f;
CGSize constraint = CGSizeMake(maxWidth, maxHeight);
// checking frame sizes
CGSize coreTextSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRangeMake(0, len), nil, constraint, &range);
// allocate glyphs and bounding box arrays for holding the result
// assuming that each character is only one glyph, which is wrong
CGGlyph *glyphs = (CGGlyph *)malloc(sizeof(CGGlyph)*len);
CTFontGetGlyphsForCharacters(coreTextFont, characters, glyphs, len);
// get bounding boxes for glyphs
CGRect *bb = (CGRect *)malloc(sizeof(CGRect)*len);
CTFontGetBoundingRectsForGlyphs(coreTextFont, kCTFontDefaultOrientation, glyphs, bb, len);
CFRelease(coreTextFont);
bb[0].origin = l.bounds.origin;
coreTextSize.width = ceilf(coreTextSize.width);
coreTextSize.height = ceilf(coreTextSize.height);
bb[0].size = coreTextSize;
l.position = CGPointMake(200.f, 100.f);
// after setting the bounds the layer gets transparent
l.bounds = bb[0];
l.opaque = YES;
return;
l.backgroundColor = CGColorCreateGenericRGB(0.f, .5f, .9f, 1.f);
free(characters);
free(glyphs);
free(bb);
}
結果文字列の境界ボックスは正しいです。分音符号で問題が発生します。バウンディング ボックスの高さが十分でないため、Ä にドットがありません。
使用するCTLineGetTypographicBounds
-(void) resizeLayer3:(CATextLayer *)l toString:(NSString *)string
{
// need to set CGFont explicitly to convert font property to a CGFontRef
CGFontRef layerFont = CGFontCreateWithFontName((CFStringRef)@"Helvetica");
l.font = layerFont;
string = l.string;
NSUInteger len = [string length];
// get characters from NSString
UniChar *characters = (UniChar *)malloc(sizeof(UniChar)*len);
CFStringGetCharacters((__bridge CFStringRef)l.string, CFRangeMake(0, [l.string length]), characters);
// Get CTFontRef from CGFontRef
CTFontRef coreTextFont = CTFontCreateWithGraphicsFont(layerFont, l.fontSize, NULL, NULL);
CFMutableAttributedStringRef attrStr = CFAttributedStringCreateMutable(kCFAllocatorDefault, 0);
CFAttributedStringReplaceString(attrStr, CFRangeMake(0, 0), (__bridge CFStringRef)string);
CFAttributedStringSetAttribute(attrStr, CFRangeMake(0, CFAttributedStringGetLength(attrStr)), kCTFontAttributeName, coreTextFont);
CTLineRef line = CTLineCreateWithAttributedString(attrStr);
CGFloat ascent;
CGFloat descent;
CGFloat width = CTLineGetTypographicBounds(line, &ascent, &descent, NULL);
CGFloat height = ascent+descent;
CGSize coreTextSize = CGSizeMake(width,height);
// get bounding boxes for glyphs
CGRect *bb = (CGRect *)malloc(sizeof(CGRect)*len);
CFRelease(coreTextFont);
bb[0].origin = CGPointZero;
coreTextSize.width = ceilf(coreTextSize.width);
coreTextSize.height = ceilf(coreTextSize.height);
bb[0].size = coreTextSize;
l.position = CGPointMake(200.f, 100.f);
// after setting the bounds the layer gets transparent
l.bounds = bb[0];
l.opaque = YES;
return;
l.backgroundColor = CGColorCreateGenericRGB(0.f, .5f, .9f, 1.f);
free(characters);
free(bb);
}
結果文字列の境界ボックスは正しいです。分音符号で問題が発生します。バウンディング ボックスの高さが十分でないため、Ä にドットがありません。
使用するCTFontGetBoundingRectsForGlyphs
-(void) resizeLayer4:(CATextLayer *)l toString:(NSString *)string
{
// need to set CGFont explicitly to convert font property to a CGFontRef
CGFontRef layerFont = CGFontCreateWithFontName((CFStringRef)@"Helvetica");
l.font = layerFont;
string = l.string;
NSUInteger len = [string length];
// get characters from NSString
UniChar *characters = (UniChar *)malloc(sizeof(UniChar)*len);
CFStringGetCharacters((__bridge CFStringRef)l.string, CFRangeMake(0, [l.string length]), characters);
// Get CTFontRef from CGFontRef
CTFontRef coreTextFont = CTFontCreateWithGraphicsFont(layerFont, l.fontSize, NULL, NULL);
// allocate glyphs and bounding box arrays for holding the result
// assuming that each character is only one glyph, which is wrong
CGGlyph *glyphs = (CGGlyph *)malloc(sizeof(CGGlyph)*len);
CTFontGetGlyphsForCharacters(coreTextFont, characters, glyphs, len);
CGPathRef glyphPath = CTFontCreatePathForGlyph(coreTextFont, glyphs[1], NULL);
CGRect rect = CGPathGetBoundingBox(glyphPath);
// get bounding boxes for glyphs
CGRect *bb = (CGRect *)malloc(sizeof(CGRect)*len);
CTFontGetBoundingRectsForGlyphs(coreTextFont, kCTFontDefaultOrientation, glyphs, bb, len);
CFRelease(coreTextFont);
l.position = CGPointMake(200.f, 100.f);
l.bounds = rect;
l.backgroundColor = CGColorCreateGenericRGB(0.f, .5f, .9f, 1.f);
free(characters);
free(glyphs);
free(bb);
}
結果文字列の境界ボックスは正しいです。分音記号自体がグリフであり、文字が別のグリフであるため、分音記号で問題が発生します。Ä は 2 つのグリフで構成されることを意味します。どうやってそれを使うことができますか?
私が見落としていて、試す価値のある他の可能性はありますか?
編集
3番目のオプションCTLineGetTypographicBounds
はうまくいくようです。CATextLayer
ただし、a の最初の行に分音記号がないという別の問題が発生しています。最初の行は、どういうわけか高さが十分ではありません。それは、ここで間違ったツリーを吠えていることを意味します。