Last active
February 2, 2018 15:07
-
-
Save 1ec5/2e63e3da1b47997c1ac231a4d501a5df to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// main.m | |
// HighRowGlyph | |
// | |
// Created by Minh Nguyen on 2018-02-01. | |
// Copyright © 2018 Mapbox. All rights reserved. | |
// | |
#import <Foundation/Foundation.h> | |
#import <Cocoa/Cocoa.h> | |
#import <CoreText/CoreText.h> | |
#import <CoreGraphics/CoreGraphics.h> | |
#define PTR_OR_ARRAY(name) (name##Ptr ?: name) | |
int main(int argc, const char * argv[]) { | |
@autoreleasepool { | |
// Glyph IDs & positions | |
NSString *str = @"Hello good World 汉语 漢語 เลขฮินดูอารบิก"; | |
NSDictionary *fontAttributes = @{ | |
(NSString *)kCTFontSizeAttribute: @24.0, | |
// (NSString *)kCTFontFamilyNameAttribute: @"Comic Sans MS", | |
}; | |
CTFontDescriptorRef descriptor = CTFontDescriptorCreateWithAttributes((CFDictionaryRef)fontAttributes); | |
CTFontRef font = CTFontCreateWithFontDescriptor(descriptor, 0.0, NULL); | |
UniChar chars[str.length]; | |
[str getCharacters:chars]; | |
CGGlyph glyphs[str.length]; | |
bool result = CTFontGetGlyphsForCharacters(font, chars, glyphs, str.length); | |
// if (!result) { | |
// return 1; | |
// } | |
for (NSUInteger i = 0; i < sizeof(glyphs) / sizeof(glyphs[0]); i++) { | |
NSLog(@"%hu", glyphs[i]); | |
} | |
NSRect rect = NSMakeRect(0, 0, 300, 300); | |
NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL | |
pixelsWide:rect.size.width | |
pixelsHigh:rect.size.height | |
bitsPerSample:8 | |
samplesPerPixel:4 | |
hasAlpha:YES | |
isPlanar:NO | |
colorSpaceName:NSDeviceRGBColorSpace | |
bitmapFormat:NSAlphaFirstBitmapFormat | |
bytesPerRow:0 | |
bitsPerPixel:0]; | |
NSGraphicsContext *context = [NSGraphicsContext graphicsContextWithBitmapImageRep:rep]; | |
CFAttributedStringRef attrStr = CFAttributedStringCreate(NULL, (CFStringRef)str, (CFDictionaryRef)fontAttributes); | |
CTLineRef line = CTLineCreateWithAttributedString(attrStr); | |
CFArrayRef runs = CTLineGetGlyphRuns(line); | |
NSArray *colors = @[NSColor.blackColor, NSColor.brownColor, NSColor.purpleColor, NSColor.redColor, NSColor.orangeColor, NSColor.yellowColor]; | |
for (NSUInteger i = 0; i < CFArrayGetCount(runs); i++) { | |
CTRunRef run = CFArrayGetValueAtIndex(runs, i); | |
CGContextSetFillColorWithColor(context.CGContext, [colors[i] CGColor]); | |
NSLog(@"Run %lu ---", (unsigned long)i); | |
NSDictionary *attrs = (NSDictionary *)CTRunGetAttributes(run); | |
NSLog(@"%@", [attrs[NSFontAttributeName] fontName]); | |
CFIndex runGlyphCount = CTRunGetGlyphCount(run); | |
const CGGlyph *runGlyphsPtr = CTRunGetGlyphsPtr(run); | |
CGGlyph *runGlyphs = NULL; | |
if (!runGlyphsPtr) { | |
runGlyphs = malloc(runGlyphCount * sizeof(CGGlyph)); | |
CTRunGetGlyphs(run, CFRangeMake(0, 0), runGlyphs); | |
} | |
for (NSUInteger j = 0; j < runGlyphCount; j++) { | |
NSLog(@"%hu", PTR_OR_ARRAY(runGlyphs)[j]); | |
} | |
CGRect runBounds = CTRunGetImageBounds(run, context.CGContext, CFRangeMake(0, 0)); | |
const CGPoint *positionsPtr = CTRunGetPositionsPtr(run); | |
CGPoint *positions = NULL; | |
if (!positionsPtr) { | |
positions = malloc(runGlyphCount * sizeof(CGGlyph)); | |
CTRunGetPositions(run, CFRangeMake(0, 0), positions); | |
} | |
CTFontRef runFont = CTFontCreateWithName((CFStringRef)[attrs[NSFontAttributeName] fontName], [attrs[NSFontSizeAttribute] doubleValue] / 2.0, NULL); | |
CTFontDrawGlyphs(runFont, PTR_OR_ARRAY(runGlyphs), PTR_OR_ARRAY(positions), runGlyphCount, context.CGContext); | |
CGRect boundingRects[runGlyphCount]; | |
CTFontGetBoundingRectsForGlyphs(runFont, kCTFontOrientationHorizontal, PTR_OR_ARRAY(runGlyphs), boundingRects, runGlyphCount); | |
CGSize advances[runGlyphCount]; | |
CTFontGetAdvancesForGlyphs(runFont, kCTFontOrientationHorizontal, PTR_OR_ARRAY(runGlyphs), advances, runGlyphCount); | |
CGSize translations[runGlyphCount]; | |
CTFontGetVerticalTranslationsForGlyphs(font, PTR_OR_ARRAY(runGlyphs), translations, runGlyphCount); | |
CGSize runAdvance = CGSizeZero; | |
for (NSUInteger j = 0; j < runGlyphCount; j++) { | |
CGRect frame = boundingRects[j]; | |
// frame.origin.x = CGRectGetMinX(runBounds) + runAdvance.width; | |
// frame.origin.y = CGRectGetMinY(runBounds) + runAdvance.height; | |
frame.origin.x += CGRectGetMinX(runBounds) + runAdvance.width; | |
frame.origin.y += /* CGRectGetMinY(runBounds) */ + runAdvance.height; | |
CGContextStrokeRectWithWidth(context.CGContext, frame, 0.5); | |
frame.origin.y += 20; | |
CGContextStrokeRectWithWidth(context.CGContext, frame, 0.5); | |
runAdvance.width += advances[j].width; | |
runAdvance.height += advances[j].height; | |
} | |
free(runGlyphs); | |
free(positions); | |
} | |
[NSGraphicsContext restoreGraphicsState]; | |
NSData *imageData = [rep representationUsingType:NSPNGFileType properties:@{}]; | |
NSURL *fileURL = [NSURL fileURLWithPath:@"/Users/mxn/Desktop/firstrun.png"]; | |
[imageData writeToURL:fileURL atomically:NO]; | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment