Как управлять границей текстового глифа

Предположим, у меня есть приложение часов, и я хочу пометить часы символами, которые могут быть в произвольном наборе символов/шрифте. Я хотел бы обрамить персонажа в рамку и максимально заполнить ее. Как я могу это сделать? Если я использую UILabel, вокруг глифа вставляется пробел. Вот примеры, показывающие две метки, обе с одинаковым шрифтом, но с разными символами. Все еврейские цифры кажутся короче арабских. Есть ли способ определить размер глифов или как-то вытолкнуть глифы, чтобы они соответствовали рамке?

введите здесь описание изображения введите здесь описание изображения

Как видите, еврейское число короче, несмотря на то, что оно добавляется к более высокому UILabel.

Изменить: после публикации я сделал первый проход с использованием основного текста, чтобы посмотреть, может ли это решить мою проблему. Кажется, что не будет. Посмотрите на эти иллюстрации, сравнивающие еврейский глиф с арабским цифровым глифом. Они желтые - это границы этикетки. Зеленый — это прямоугольник глифа, указанный в основном тексте. Я надеялся получить прямоугольник заподлицо с глифом, но похоже, что глифы на иврите включают пространство над и рядом с тем, что я ожидал быть глифом. Есть ли что-то еще, что я должен проверить? Ивритская цифра Арабская цифра


person Victor Engel    schedule 14.11.2017    source источник
comment
Взгляните на CTFont, особенно на раздел Получение данных глифов: developer.apple.com/documentation/coretext/ctfont-q6r   -  person DonMag    schedule 14.11.2017
comment
Я посмотрел на это, но он получает данные для шрифта, а не для конкретных глифов.   -  person Victor Engel    schedule 14.11.2017
comment
Я беру это обратно. Похоже, для массивов глифов доступны граничные данные. Я посмотрю на это ....   -  person Victor Engel    schedule 14.11.2017
comment
Зеленые прямоугольники исходят из CTFontGetBoundingRectsForGlyphs. Все они, как и ожидалось, для арабских цифр, и во всех над ними есть дополнительное пространство для еврейских цифр.   -  person Victor Engel    schedule 22.11.2017


Ответы (1)


Я не знаю, используете ли вы Obj-C или Swift, но вы можете вставить это на страницу Swift Playground, чтобы увидеть результат:

Незначительные правки

import UIKit
import CoreText
import PlaygroundSupport


class PathView: UIView {

    var myPath: UIBezierPath?

    override func draw(_ rect: CGRect) {

        if let pth = myPath {

            UIColor.red.setStroke()

            // glyph path is inverted, so flip vertically
            let flipY = CGAffineTransform(scaleX: 1, y: -1.0)

            // glyph path may be offset on the x coord, and by the height (because it's flipped)
            let translate = CGAffineTransform(translationX: -pth.bounds.origin.x, y: pth.bounds.size.height + pth.bounds.origin.y)

            // apply the transforms
            pth.apply(flipY)
            pth.apply(translate)

            // stroke the path
            pth.stroke()

            // print the modified path for debug / reference
            print(pth)

        }

    }

}

class TestViewController : UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // blue background so we can see framing
        view.backgroundColor = UIColor(red: 0.25, green: 0.5, blue: 01.0, alpha: 1.0)

        // use a large font so we can see it easily
        let font = UIFont(name: "Times", size: 160)!

        // Hebrew character for 8
        var unichars = [UniChar]("ח".utf16)
        unichars = [UniChar]("י".utf16)

        // init glyphs array
        var glyphs = [CGGlyph](repeatElement(0, count: unichars.count))

        let gotGlyphs = CTFontGetGlyphsForCharacters(font, &unichars, &glyphs, unichars.count)

        if gotGlyphs {
            // get the cgPath for the character
            let cgpath = CTFontCreatePathForGlyph(font, glyphs[0], nil)!

            // convert it to a UIBezierPath
            let path = UIBezierPath(cgPath: cgpath)

            var r = path.bounds

            // let's show it at 40,40
            r = r.offsetBy(dx: 40.0, dy: 40.0)

            let pView = PathView(frame: r)
            pView.backgroundColor = .white
            pView.myPath = path

            view.addSubview(pView)

            // print bounds and path data for debug / reference
            print("bounds of path:", path.bounds)
            print()
            print(path)
            print()
        }

    }

}

let vc = TestViewController()
PlaygroundPage.current.liveView = vc

Требуется много проверки/обработки ошибок, но это может дать вам хорошее начало для поиска и использования границ фактических глифов символов (вместо рамок меток).

Результат:

введите здесь описание изображения введите здесь описание изображения

person DonMag    schedule 22.11.2017
comment
Таким образом, вместо того, чтобы запрашивать ограничивающую рамку, вы запрашиваете путь глифа и получаете для него границу. CTFontGetBoundingRectsForGlyphs не имеет ничего общего с рамкой или границами метки. - person Victor Engel; 23.11.2017
comment
По сути, да. Однако это немного сложно... Если вы, например, запустите этот код и посмотрите на границы пути, вы увидите (6.875, -1.953125, 62.4247159090909, 89.921875), что на первый взгляд немного странно. Отрицательный Y? Я недостаточно знаю о характеристиках шрифта/глифов, чтобы объяснить... но, надеюсь, это даст вам достаточно, чтобы добраться до места назначения. - person DonMag; 23.11.2017
comment
Да, похоже, что это так. Я подробно рассмотрю ваш код, когда у меня будет время. Но, похоже, он может получить именно то, что мне нужно. Спасибо. Я, вероятно, приму это как ответ через пару дней. Однако в дополнение к получению решения я пытаюсь понять структуру. Возможно, в полях с глифами есть место для других знаков, которые иногда могут быть включены для иврита, но, похоже, я должен иметь возможность запрашивать границы этих областей. P.S. В настоящее время я использую Objective-C, но я кодирую в обоих, так что это нормально. - person Victor Engel; 23.11.2017
comment
Кстати, похоже, проблема с c : unichar = 0x05d9. Я думаю. Я еще не удосужился понять, почему он кажется усеченным. - person Victor Engel; 23.11.2017
comment
Как я уже упоминал, я многого не знаю о характеристиках шрифта/глифа... Я сделал пару небольших правок... если вы возьмете этот обновленный код, он должен работать (или, по крайней мере, быть близким к работе) с обоими "ח" и "י" (просто закомментируйте/раскомментируйте назначение unichars). - person DonMag; 23.11.2017
comment
Я только что сделал те же самые изменения на своей стороне, прежде чем я увидел ваше сообщение. :) Кстати, мне не нравится использовать строковые литералы для символов с противоположным направлением, потому что выбор странный, а иногда возникают артефакты отображения в результате изменения направления. - person Victor Engel; 23.11.2017