Mac寫入文字的像素寬度

參考文檔:

https://en.wikipedia.org/wiki/Core_Text

https://developer.apple.com/library/content/documentation/TextFonts/Conceptual/CocoaTextArchitecture/FontHandling/FontHandling.html#//apple_ref/doc/uid/TP40009459-CH5-SW18

https://developer.apple.com/library/content/documentation/TextFonts/Conceptual/CocoaTextArchitecture/TypoFeatures/TextSystemFeatures.html#//apple_ref/doc/uid/TP40009459-CH6-51627-BBCCHIFF

https://developer.apple.com/library/content/documentation/StringsTextFonts/Conceptual/CoreText_Programming/Introduction/Introduction.html#//apple_ref/doc/uid/TP40005533 

#include <iostream>
#include <string>
#include <CoreText/CoreText.h>
#include <CoreFoundation/CFBase.h>
#include <iomanip>

void GetTextExtent(const std::wstring fontname, int fontsize, const std::wstring str, float* width, float* height) {
    if (str.empty())
    {
        *width = 0;
        *height = 0;
        return;
    }

    CFStringRef nameRef = CFStringCreateWithBytes(kCFAllocatorDefault,
                                                 reinterpret_cast<const UInt8*>(fontname.c_str()),
                                                 fontname.size() * sizeof(wchar_t),
                                                 kCFStringEncodingUTF32LE,
                                                 false);
    
    CTFontRef fontRef = CTFontCreateWithName(nameRef, fontsize, 0);

    CFStringRef strRef = CFStringCreateWithBytes(kCFAllocatorDefault,
                                              reinterpret_cast<const UInt8*>(str.c_str()),
                                              str.size() * sizeof(wchar_t),
                                              kCFStringEncodingUTF32LE,
                                              false);
    
    CFStringRef keys[] = { kCTFontAttributeName };
    CFTypeRef values[] = { fontRef };
    CFDictionaryRef font_attributes = CFDictionaryCreate(0, (const void **)keys, (const void **)values, sizeof(keys)/sizeof(keys[0]),
                                                         &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
    CFAttributedStringRef attrStr = CFAttributedStringCreate(0, strRef, font_attributes);
    CTLineRef line = CTLineCreateWithAttributedString(attrStr);
    CGFloat a, d, l, w;
    w = CTLineGetTypographicBounds(line, &a, &d, &l);
    
    
    if (width)
        *width = w;
    if (height)
        *height = a + d + l;

    CFRelease(nameRef);
    CFRelease(strRef);
    CFRelease(fontRef);
}


void GetTextExtent2(const std::wstring fontname, int fontsize, const std::wstring str, float* width, float* height) {
    if (str.empty())
    {
        *width = 0;
        *height = 0;
        return;
    }
    
    CFStringRef strRef = CFStringCreateWithBytes(kCFAllocatorDefault,
                                              reinterpret_cast<const UInt8*>(str.c_str()),
                                              str.size() * sizeof(wchar_t),
                                              kCFStringEncodingUTF32LE,
                                              false);
    
    CFStringRef nameRef = CFStringCreateWithBytes(kCFAllocatorDefault,
                                                  reinterpret_cast<const UInt8*>(fontname.c_str()),
                                                  fontname.size() * sizeof(wchar_t),
                                                  kCFStringEncodingUTF32LE,
                                                  false);
    
    CTFontRef fontRef = CTFontCreateWithName(nameRef, fontsize, 0);
    
    CFIndex count = CFStringGetLength(strRef);
    
    UniChar *characters = (UniChar *)malloc(sizeof(UniChar) * count);
    CGGlyph *glyphs = (CGGlyph *)malloc(sizeof(CGGlyph) * count);
    
    CFStringGetCharacters(strRef, CFRangeMake(0, count), characters);
    CTFontGetGlyphsForCharacters(fontRef, characters, glyphs, count);
    
    CGSize *sizeCore = (CGSize*)malloc(count * sizeof(CGSize));
    
    double adv = CTFontGetAdvancesForGlyphs (fontRef,
                                             kCTFontOrientationHorizontal,
                                             glyphs,
                                             sizeCore,
                                             count);
    *width = adv;
    *height = sizeCore->height;
    
    CFRelease(strRef);
    CFRelease(nameRef);
    CFRelease(fontRef);
    free(characters);
    free(glyphs);
    free(sizeCore);
}

void GetTextExtent3(const std::wstring fontname, int fontsize, const std::wstring str, float* width, float* height) {
    if (str.empty())
    {
        *width = 0;
        *height = 0;
        return;
    }
    
    CFStringRef strRef = CFStringCreateWithBytes(kCFAllocatorDefault,
                                                 reinterpret_cast<const UInt8*>(str.c_str()),
                                                 str.size() * sizeof(wchar_t),
                                                 kCFStringEncodingUTF32LE,
                                                 false);
    
    CFStringRef nameRef = CFStringCreateWithBytes(kCFAllocatorDefault,
                                                  reinterpret_cast<const UInt8*>(fontname.c_str()),
                                                  fontname.size() * sizeof(wchar_t),
                                                  kCFStringEncodingUTF32LE,
                                                  false);
    
    CTFontRef fontRef = CTFontCreateWithName(nameRef, fontsize, 0);
    CFIndex count = CFStringGetLength(strRef);
    UniChar *characters = (UniChar *)malloc(sizeof(UniChar) * count);
    CGGlyph *glyphs = (CGGlyph *)malloc(sizeof(CGGlyph) * count);
    
    CFStringGetCharacters(strRef, CFRangeMake(0, count), characters);
    CTFontGetGlyphsForCharacters(fontRef, characters, glyphs, count);
    
    CGSize *sizeCore = (CGSize*)malloc(count * sizeof(CGSize));
    CGRect *rectCore = (CGRect*)malloc(count * sizeof(CGRect));
    
    double adv = CTFontGetAdvancesForGlyphs (fontRef,
                                             kCTFontOrientationHorizontal,
                                             glyphs,
                                             sizeCore,
                                             count);
    // rect 是第一個字符的寬度
    CGRect rect = CTFontGetBoundingRectsForGlyphs (fontRef,
                                                   kCTFontOrientationHorizontal,
                                                   glyphs,
                                                   rectCore,
                                                   count);
    double kerning = adv - rect.size.width;
    std::cout << "return CGRect.size.width : " << ((CGRect*)rectCore)->size.width << std::endl;
    std::cout << "CGRect : ";
    float sumwidth = 0.f;
    
    for (int i = 0; i < count; ++i) {
        sumwidth += rect.size.width;
        std::cout << " " << i << " : " << rect.size.width;
    }
    std::cout << std::endl;
    
    std::wcout << str << "\tsum    : " << sumwidth << std::endl;
    std::wcout << str << "\tadv    : " << adv << std::endl;
    std::wcout << str << "\tkerning: " << kerning << std::endl;
    
    free(characters);
    free(glyphs);
    free(sizeCore);
    free(rectCore);
}

typedef void (*func)(const std::wstring fontname, int fontsize, const std::wstring str, float* width, float* height);

void test1(func f) {
    std::wstring fontname = L"Arial";
    int fontsize = 16;
    std::wstring str;
    for (wchar_t wc = 'A'; wc < 'z'; ++wc ) {
        str.append(&wc , 1);

        float w, h;
        f(fontname, fontsize, str, &w, &h);
        std::wcout << str << "\t" << fontname << "\t" << fontsize << "\t" << std::setw(10) << w << "\t" << h << "\t"  << std::endl;
    }
}

void test2(func f) {
    std::wstring fontname = L"Arial";
    int fontsize = 16;
    for (wchar_t wc = 'A'; wc < 'z'; ++wc ) {
        std::wstring str;
        str.append(&wc , 1);
        
        float w, h;
        f(fontname, fontsize, str, &w, &h);
        std::wcout << str << "\t" << fontname << "\t" << fontsize << "\t" << std::setw(10) << w << "\t" << h << "\t"  << std::endl;
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章