es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Dibuja gráficos y exporta con precisión de píxeles con CoreGraphics.

Vi algunas preguntas aquí en stackoverflow, pero ninguna de ellas resolvió mi problema. Lo que quiero hacer es subclasificar NSView y dibujar algunas formas en ella. Luego quiero exportar/guardar los gráficos creados en un archivo png. Y aunque el dibujo es bastante simple, quiero poder almacenar la imagen con precisión de píxeles, ya que sé que el dibujo se realiza en puntos en lugar de píxeles. Entonces lo que estoy haciendo es anular el método draw() para dibujar cualquier gráfico de la siguiente manera:

override func draw(_ dirtyRect: NSRect) {

    super.draw(dirtyRect)

    NSColor.white.setFill()
    dirtyRect.fill()

    NSColor.green.setFill()
    NSColor.green.setStroke()

    currentContext?.beginPath()
    currentContext?.setLineWidth(1.0)
    currentContext?.setStrokeColor(NSColor.green.cgColor)
    currentContext?.move(to: CGPoint(x: 0, y: 0))
    currentContext?.addLine(to: CGPoint(x: self.frame.width, y: self.frame.height))
    currentContext?.closePath()

}

Y aunque en la pantalla se ve bien, después de guardar esto en un archivo no es lo que esperaba. Configuré el ancho de línea en 1, pero en el archivo exportado tiene 2 píxeles de ancho. Y para guardar la imagen, creo NSImage a partir de la vista actual:

func getImage() -> NSImage? {

let size = self.bounds.size
let imageSize = NSMakeSize(size.width, size.height)

guard let imageRepresentation = self.bitmapImageRepForCachingDisplay(in: self.bounds) else {
    return nil
}

imageRepresentation.size = imageSize
self.cacheDisplay(in: self.bounds, to: imageRepresentation)
let image = NSImage(size: imageSize)
image.addRepresentation(imageRepresentation)
return image

}

Y luego esta imagen se guarda en un archivo:

do {
guard let image = self.canvasView?.getImage() else {
return
}

let imageRep = image.representations.first as? NSBitmapImageRep
let data = imageRep?.representation(using: .png, properties: [:])

try data?.write(to: url, options: .atomic)

} catch {
print(error.localizedDescription)
}

¿Tienes algún consejo sobre qué estoy haciendo mal?

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    Parece que el problema que estás enfrentando está relacionado con la diferencia entre puntos y píxeles al dibujar gráficos en una pantalla. Para garantizar precisión de píxeles, debes tener en cuenta la resolución de la pantalla y ajustar tu código en consecuencia.

    En primer lugar, puedes obtener la resolución de la pantalla utilizando la propiedad backingScaleFactor de NSView. Este valor representa la relación entre puntos y píxeles, y generalmente es 1 en pantallas no retina y 2 en pantallas retina.

    A continuación, debes ajustar tu código para utilizar valores de píxeles en lugar de puntos al dibujar líneas y formas. Por ejemplo, si quieres dibujar una línea de 1 píxel de ancho, puedes utilizar el siguiente código:

    let anchoDeLínea = 1.0 / self.backingScaleFactor
    currentContext?.setLineWidth(anchoDeLínea)
    

    Esto asegurará que la línea tenga 1 píxel físico de ancho, independientemente de la resolución de la pantalla.

    De manera similar, al crear una representación de imagen de mapa de bits de tu vista, debes establecer su tamaño en píxeles, no en puntos. Para hacerlo, puedes utilizar el siguiente código:

    let tamañoEnPíxeles = NSSize(width: tamaño.width * self.backingScaleFactor, height: tamaño.height * self.backingScaleFactor)
    let representaciónDeImagen = NSBitmapImageRep(bitmapDataPlanes: nil, pixelsWide: Int(tamañoEnPíxeles.width), pixelsHigh: Int(tamañoEnPíxeles.height), bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false, colorSpaceName: NSColorSpaceName.calibratedRGB, bytesPerRow: 0, bitsPerPixel: 0)!
    

    Esto creará una representación de imagen de mapa de bits que tiene el mismo tamaño que tu vista en píxeles, en lugar de en puntos.

    Finalmente, al guardar la imagen en un archivo PNG, puedes utilizar la opción compressionFactor para controlar la calidad y el tamaño del archivo de la imagen. Por ejemplo, puedes utilizar un valor de 1.0 para obtener la mejor calidad pero un tamaño de archivo más grande, o un valor más cercano a 0 para obtener un tamaño de archivo más pequeño pero una calidad más baja. Aquí tienes un ejemplo:

    let propiedades: [NSBitmapImageRep.PropertyKey: Any] = [.compressionFactor: 1.0]
    let datos = imageRep?.representation(using: .png, properties: propiedades)
    

    Siguiendo estos consejos, deberías poder exportar tus gráficos con precisión de píxeles y obtener los resultados esperados.

Comments are closed.