问题
I'm using the following code to draw text on the right side on an image
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()
As you can see there is some excessive spacing from the right side.How can i fix it?
Update:
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()
}
}
}
Update: This is the desired result
回答1:
Use the following translation
context.translateBy(x: self.bounds.maxX, y: (rect.height - size.width) / 2)
回答2:
I hope you understand how CGContext transforms work, if not, learn it.
One of the simplest implementations of your problem is like this: the text is blue rectangle, you want to draw a red rectangle.
So it's enough to calculate a shift transform, then rotate-90. A shift transform in this case is a left-bottom of the blue rectangle, and at the same time the right-bottom of the red rectangle.
Your DemoView
can look like this:
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)
}
}
In this code, the centerInView
param is the center of your red rectangle.
The result looks like this:
Please note that we fill the entire view with red color, then we render the image, then we render the text. No excessive spacing is present. If it was present, we would see red lines below the image.
You can download the demo here.
And please don't draw everything in a one draw(_ rect: NSRect)
call - try to extract at least the text drawing func - it'll give you much more flexibility in defining the variables of the problem.
UPDATE:
I you need the text to be "flipped", so its bottom side points toward the center, the transform can look like this:
context.translateBy(x: textCenter.x-textSize.height/2, y: textCenter.y+textSize.width/2)
context.rotate(by: -CGFloat.pi / 2)
and the text will look like this:
来源:https://stackoverflow.com/questions/61676256/drawing-text-on-right-side-of-nsimage-unwanted-spacing