Рисование текста на правой стороне изображения NSImage - нежелательные интервалы - PullRequest
0 голосов
/ 08 мая 2020

Я использую следующий код для рисования текста с правой стороны изображения

         im.lockFocus()
         if let context = NSGraphicsContext.current?.cgContext {
         context.saveGState()
         let size = text.size(withAttributes: textFontAttributes)
         context.translateBy(x: imageRect.width-size.height, y: (imageRect.height - size.width) / 2)
         context.rotate(by: CGFloat.pi / 2)
         text.draw(at: .zero, withAttributes: textFontAttributes)
         context.restoreGState()
         im.unlockFocus()

Как вы можете видеть, с правой стороны слишком большой интервал. Как это исправить?

enter image description here

Обновление:

class DemoView: NSView {
    override func draw(_ rect: NSRect) {

        // .. your drawing code here

        NSColor.red.set()  // just for demo
        rect.fill()        // just for demo

        if let context = NSGraphicsContext.current?.cgContext {
            context.saveGState()

            let text: NSString = "Hello World"
            let attributes = [
                NSAttributedString.Key.foregroundColor: NSColor.white, 
                NSAttributedString.Key.font: NSFont.systemFont(ofSize: 24)
            ]

            let size = text.size(withAttributes: attributes)
            context.translateBy(x: imageRect.width-size.height, y: (rect.height - size.width) / 2)
            context.rotate(by: CGFloat.pi / 2)

            text.draw(at: .zero, withAttributes: attributes)

            context.restoreGState()
        }
    }
}

Обновление: это желаемый результат enter image description here

Ответы [ 2 ]

1 голос
/ 10 мая 2020

Надеюсь, вы понимаете, как работают преобразования CGContext, если нет, изучите это.

Одна из простейших реализаций вашей проблемы выглядит так: текст представляет собой синий прямоугольник, вы хотите нарисовать красный прямоугольник.

enter image description here

Итак, достаточно вычислить преобразование сдвига, затем повернуть на 90. Преобразование сдвига в этом случае - это левый нижний угол синего прямоугольника и в то же время правый нижний угол красного прямоугольника.

Ваш DemoView может выглядеть так:

class DemoView: NSView {
    override func draw(_ rect: NSRect) {

        let image = NSImage(named: "test_image.jpg")!

        if let context = NSGraphicsContext.current?.cgContext {
            context.saveGState()

            NSColor.red.set()  // just for demo
            rect.fill()        // just for demo

            image.draw(in: rect)

            let text: NSString = "Hello World"
            let attributes = [
                NSAttributedString.Key.foregroundColor: NSColor.white,
                NSAttributedString.Key.font: NSFont.systemFont(ofSize: 24)
            ]

            let size = bounds.size
            let rotatedTextCenter = CGPoint(x: size.width*0.8, y: size.height/2)

            // draw the the circle in desired center to check if text was transformed correctly
            drawCircleInView(context: context, center: rotatedTextCenter)

            // draw the rotated text so its center fits the circle center
            drawAttributedTextInView(text: text, textAttributes: attributes, context: context, viewSize: size, centerInView: rotatedTextCenter)

            context.restoreGState()
        }
    }

    func drawCircleInView(context: CGContext, center: CGPoint) {
        context.setLineWidth(5)
        context.setFillColor(NSColor.red.cgColor)
        context.addArc(center: center, radius: 10, startAngle: 0, endAngle: CGFloat.pi*2, clockwise: false)
        context.fillPath()
    }

    func drawAttributedTextInView(text: NSString,
                                  textAttributes: [NSAttributedString.Key:Any],
                                  context: CGContext,
                                  viewSize: CGSize,
                                  centerInView textCenter: CGPoint) {

        // we assume everything else was already drawn and context has identity transform for the simplicity

        let textSize = text.size(withAttributes: textAttributes)

        context.translateBy(x: textCenter.x+textSize.height/2, y: textCenter.y-textSize.width/2)
        context.rotate(by: CGFloat.pi / 2)

        text.draw(at: .zero, withAttributes: textAttributes)
    }
}

В этом коде параметр centerInView - это центр вашего красного прямоугольника.

Результат выглядит так: enter image description here

Обратите внимание что мы заполняем весь вид красным цветом, затем визуализируем изображение, затем визуализируем текст. Нет чрезмерного интервала. Если бы он присутствовал, мы бы увидели красные линии под изображением.

Вы можете скачать демо здесь .

И, пожалуйста, не рисуйте все за один звонок draw(_ rect: NSRect) - попробуйте извлечь по как минимум забавное рисование текста c - это даст вам гораздо больше гибкости в определении переменных задачи.

ОБНОВЛЕНИЕ :

Мне нужен текст быть "перевернутым", чтобы его нижняя сторона была направлена ​​к центру, преобразование может выглядеть следующим образом:

context.translateBy(x: textCenter.x-textSize.height/2, y: textCenter.y+textSize.width/2)
context.rotate(by: -CGFloat.pi / 2)

, а текст будет выглядеть так: enter image description here

1 голос
/ 08 мая 2020

Используйте следующий перевод

demo

context.translateBy(x: self.bounds.maxX, y: (rect.height - size.width) / 2)
...