Рисование простой линии на изображении в формате JPEG

Я снова застрял с, казалось бы, простым вопросом.

Я загрузил файл JPEG в CGImage. Я получил правильные значения ширины и высоты (в пикселях) и смог показать «myImage» в контроллере ImageView. Но я хотел добавить немного графики к этому изображению и обнаружил, что вместо этого я должен получить его в NSImage. Я так и сделал, но получил разные (пропорциональные) значения ширины и высоты: 595,08 вместо 1653 и 841,68 вместо 2338 соответственно.

Я попытался создать NSCGContext из CGContext «gc» для рисования (простая линия и прямоугольник), что привело к «Значению необязательного типа» CGContext? не развернуто, вы хотели использовать '!' или '?'?"... Я потерялся...

// with NSData
//
let imageAsData = try Data(contentsOf: chosenFiles[0])
let imageProvider = CGDataProvider(data: imageAsData as CFData)
var myImage = CGImage(jpegDataProviderSource: imageProvider!, decode: nil, shouldInterpolate: true, intent: .defaultIntent)
let imageWidth = myImage!.width
let imageHeight = myImage!.height

// with NSImage, now
//
let imageAsNSImage=NSImage(contentsOf: chosenFiles[0])
let imageSize=imageAsNSImage?.size      // ---> 0.36 * pixels 

// creating a CG context and drawing
//
let colorSpace:CGColorSpace = CGColorSpaceCreateDeviceRGB()
let gc = CGContext(data: nil, width: imageWidth, height: imageHeight, bitsPerComponent: 8, bytesPerRow: 0,space: colorSpace, bitmapInfo: CGImageAlphaInfo.noneSkipFirst.rawValue)
let NSGContext = NSGraphicsContext(cgContext: gc, flipped: true)
let currentContext = NSGraphicsContext.current()  // Cocoa GC object appropriate for the current drawing environment
NSGraphicsContext.saveGraphicsState()
NSGraphicsContext.current = NSGContext
NSGContext?.beginPath()
NSGContext?.setStrokeColor(redColor)
NSGContext?.setLineWidth(50.0)
NSGContext?.move(to: targetStart)
NSGContext?.addLine(to: targetEnd)
NSGContext?.setStrokeColor(grayColor)
NSGContext?.setFillColor(grayColor)
NSGContext?.addRect(ROIRect)
NSGContext?.closePath()
NSGContext.restoreGraphicsState()
imageAsNSImage?.draw(at: NSZeroPoint, from: NSZeroRect, operation: NSCompositeSourceOver, fraction: 1.0)
imageAsNSImage?.unlockFocus()
NSGraphicsContext.setcurrent(currentContext)
myImageView.image = imageAsNSImage  // image & drawings should show in View

person user8889350    schedule 29.12.2017    source источник
comment
Никто не знает, под каким классом вы пишете свой код. С какой целью вы создаете объект CGImage?   -  person El Tomato    schedule 30.12.2017
comment
Я создал CGImage для последующего доступа к пикселям (здесь не показано). Мне нужно обнаружить линию в ROI (области интереса), используя вероятностное преобразование Хафа, которое уже более или менее работает... В любом случае, NSImage должен показывать обрабатываемое изображение в ImageView, на котором я хочу нарисовать целевая линия (желтая) и область интереса (серая). Изображения сканируются и должны быть исправлены/масштабированы/переведены, чтобы обнаруженная линия соответствовала целевой строке. Это сделано для улучшения результатов Оптимального распознавания меток.   -  person user8889350    schedule 30.12.2017


Ответы (2)


Рисование простой линии на изображении в формате JPEG

// load JPEG from main bundle
guard let path = Bundle.main.pathForImageResource(NSImage.Name("picture.jpg")),
      let image = NSImage(contentsOfFile: path)
else { fatalError() }
let size = image.size

image.lockFocus()  // prepare image for drawing

NSColor.red.setStroke()
NSBezierPath.strokeLine(from: .zero, to: NSPoint(x: size.width, y: size.height))

image.unlockFocus()  // drawing commands done

Приведенный выше код обводит красную линию из левого нижнего угла в правый верхний. Если у вас есть NSImageView под рукой, вы можете использовать изображение напрямую:

@IBOutlet weak var imageView: NSImageView!
...
imageView.image = image
person djromero    schedule 31.12.2017
comment
Спасибо, djromero. Это очень помогает, и элегантность решения меня так расстраивает. Однако начало координат (0,0), как и ожидалось, находится в левом нижнем углу изображения, а размер не в пикселях, как я упоминал в своем исходном сообщении. Любая мысль? - person user8889350; 31.12.2017
comment
При этом я получаю NSImage того же размера, что и CGImage, и я могу рисовать линии и отображать NSImage, а также работать на уровне пикселей для преобразования Хафа... но источник NSImage все еще находится в точке нижний левый угол! let imageAsData = try Data(contentsOf: selectedFiles[0]) let imageProvider = CGDataProvider(data: imageAsData as CFData) var myImage = CGImage(jpegDataProviderSource: imageProvider!, декодировать: nil, shouldInterpolate: true, намерение: .defaultIntent) let imageAsNSImage= NSImage(cgImage: myImage!, размер: NSZeroSize) - person user8889350; 31.12.2017

Спасибо djromero, вот решение, которое я только что нашел:

// Load the JPEG image from disk into a CGImage
//
let imageAsData = try Data(contentsOf: chosenFiles[0])
let imageProvider = CGDataProvider(data: imageAsData as CFData)
var myImage = CGImage(jpegDataProviderSource: imageProvider!, decode: nil, shouldInterpolate: true, intent: .defaultIntent)

// Create a NSImage from the CGImage (with the same width and height in pixels)
//
let imageAsNSImage=NSImage(cgImage: myImage!, size: NSZeroSize)

// Drawing a simple line
//
imageAsNSImage.lockFocusFlipped(true) // Otherwise, the origin is at the lower left corner
NSColor.red.setStroke()
NSBezierPath.strokeLine(from: targetStart, to: targetEnd)
imageAsNSImage.unlockFocus()

// Show the NSImage in the NSImageView
//
myImageView.image = imageAsNSImage
person user8889350    schedule 31.12.2017