Skip to content

Instantly share code, notes, and snippets.

@1ec5
Last active February 2, 2018 15:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 1ec5/2e63e3da1b47997c1ac231a4d501a5df to your computer and use it in GitHub Desktop.
Save 1ec5/2e63e3da1b47997c1ac231a4d501a5df to your computer and use it in GitHub Desktop.
//
// 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