2016-12-11 2 views
-1

Il existe de nombreuses questions sur la création d'un outil Gomme dans CoreGraphics. Je ne peux pas trouver celui qui correspond à "pixilated".Swift - pourquoi mon outil Gomme est-il pixélisé?

Voici la situation. Je joue avec un projet de dessin simple. Les outils de stylo fonctionnent bien. L'outil Gomme est horriblement pixélisé. Voici une capture d'écran de ce que je veux dire:

enter image description here

est ici le code de dessin que je utilise (mise à jour):

// DrawingView 
// 
// 
// Created by David DelMonte on 12/9/16. 
// Copyright © 2016 David DelMonte. All rights reserved. 
// 


import UIKit 


public protocol DrawingViewDelegate { 
    func didBeginDrawing(view: DrawingView) 
    func isDrawing(view: DrawingView) 
    func didFinishDrawing(view: DrawingView) 
    func didCancelDrawing(view: DrawingView) 
} 



open class DrawingView: UIView { 

    //initial settings 
    public var lineColor: UIColor = UIColor.black 
    public var lineWidth: CGFloat = 10.0 
    public var lineOpacity: CGFloat = 1.0 
    //public var lineBlendMode: CGBlendMode = .normal 

    //used for zoom actions 
    public var drawingEnabled: Bool = true 

    public var delegate: DrawingViewDelegate? 

    private var currentPoint: CGPoint = CGPoint() 
    private var previousPoint: CGPoint = CGPoint() 
    private var previousPreviousPoint: CGPoint = CGPoint() 

    private var pathArray: [Line] = [] 
    private var redoArray: [Line] = [] 

    var toolType: Int = 0 

    let π = CGFloat(M_PI) 
    private let forceSensitivity: CGFloat = 4.0 


    private struct Line { 
     var path: CGMutablePath 
     var color: UIColor 
     var width: CGFloat 
     var opacity: CGFloat 
     //var blendMode: CGBlendMode 

     init(path : CGMutablePath, color: UIColor, width: CGFloat, opacity: CGFloat) { 
      self.path = path 
      self.color = color 
      self.width = width 
      self.opacity = opacity 
      //self.blendMode = blendMode 
     } 
    } 

    override public init(frame: CGRect) { 
     super.init(frame: frame) 
     self.backgroundColor = UIColor.clear 
    } 

    required public init?(coder aDecoder: NSCoder) { 
     super.init(coder: aDecoder) 
     self.backgroundColor = UIColor.clear 
    } 

    override open func draw(_ rect: CGRect) { 
     let context : CGContext = UIGraphicsGetCurrentContext()! 

     for line in pathArray { 
      context.setLineWidth(line.width) 
      context.setAlpha(line.opacity) 
      context.setLineCap(.round) 

      switch toolType { 
      case 0: //pen 

       context.setStrokeColor(line.color.cgColor) 
       context.addPath(line.path) 
       context.setBlendMode(.normal) 

       break 

      case 1: //eraser 

       context.setStrokeColor(UIColor.clear.cgColor) 
       context.addPath(line.path) 
       context.setBlendMode(.clear) 

       break 

      case 3: //multiply 

       context.setStrokeColor(line.color.cgColor) 
       context.addPath(line.path) 
       context.setBlendMode(.multiply) 

       break 

      default: 
       break 
      } 

      context.beginTransparencyLayer(auxiliaryInfo: nil) 
      context.strokePath() 
      context.endTransparencyLayer() 
     } 
    } 




    override open func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { 
     guard drawingEnabled == true else { 
      return 
     } 

     self.delegate?.didBeginDrawing(view: self) 
     if let touch = touches.first as UITouch! { 
      //setTouchPoints(touch, view: self) 
      previousPoint = touch.previousLocation(in: self) 
      previousPreviousPoint = touch.previousLocation(in: self) 
      currentPoint = touch.location(in: self) 

      let newLine = Line(path: CGMutablePath(), color: self.lineColor, width: self.lineWidth, opacity: self.lineOpacity) 
      newLine.path.addPath(createNewPath()) 
      pathArray.append(newLine) 
     } 
    } 

    override open func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) { 
     guard drawingEnabled == true else { 
      return 
     } 

     self.delegate?.isDrawing(view: self) 
     if let touch = touches.first as UITouch! { 
      //updateTouchPoints(touch, view: self) 
      previousPreviousPoint = previousPoint 
      previousPoint = touch.previousLocation(in: self) 
      currentPoint = touch.location(in: self) 

      let newLine = createNewPath() 
      if let currentPath = pathArray.last { 
       currentPath.path.addPath(newLine) 
      } 
     } 
    } 

    override open func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { 
     guard drawingEnabled == true else { 
      return 
     } 


    } 

    override open func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) { 
     guard drawingEnabled == true else { 
      return 
     } 


    } 



    public func canUndo() -> Bool { 
     if pathArray.count > 0 {return true} 
     return false 
    } 

    public func canRedo() -> Bool { 
     return redoArray.count > 0 
    } 


    public func undo() { 
     if pathArray.count > 0 { 

      redoArray.append(pathArray.last!) 
      pathArray.removeLast() 
     } 

     setNeedsDisplay() 
    } 

    public func redo() { 
     if redoArray.count > 0 { 
      pathArray.append(redoArray.last!) 
      redoArray.removeLast() 
     } 
     setNeedsDisplay() 
    } 

    public func clearCanvas() { 
     pathArray = [] 
     setNeedsDisplay() 
    } 



    private func createNewPath() -> CGMutablePath { 
     //print(#function) 
     let midPoints = getMidPoints() 
     let subPath = createSubPath(midPoints.0, mid2: midPoints.1) 
     let newPath = addSubPathToPath(subPath) 
     return newPath 
    } 

    private func calculateMidPoint(_ p1 : CGPoint, p2 : CGPoint) -> CGPoint { 
     //print(#function) 
     return CGPoint(x: (p1.x + p2.x) * 0.5, y: (p1.y + p2.y) * 0.5); 
    } 

    private func getMidPoints() -> (CGPoint, CGPoint) { 
     //print(#function) 
     let mid1 : CGPoint = calculateMidPoint(previousPoint, p2: previousPreviousPoint) 
     let mid2 : CGPoint = calculateMidPoint(currentPoint, p2: previousPoint) 
     return (mid1, mid2) 
    } 

    private func createSubPath(_ mid1: CGPoint, mid2: CGPoint) -> CGMutablePath { 
     //print(#function) 
     let subpath : CGMutablePath = CGMutablePath() 
     subpath.move(to: CGPoint(x: mid1.x, y: mid1.y)) 
     subpath.addQuadCurve(to: CGPoint(x: mid2.x, y: mid2.y), control: CGPoint(x: previousPoint.x, y: previousPoint.y)) 
     return subpath 
    } 

    private func addSubPathToPath(_ subpath: CGMutablePath) -> CGMutablePath { 
     //print(#function) 
     let bounds : CGRect = subpath.boundingBox 

     let drawBox : CGRect = bounds.insetBy(dx: -0.54 * lineWidth, dy: -0.54 * lineWidth) 
     self.setNeedsDisplay(drawBox) 
     return subpath 
    } 
} 

MISE À JOUR:

Je remarque que chaque touche de gomme est carré. S'il vous plaît voir la deuxième image pour montrer plus en détail:

enter image description here

Je réécrit alors un code tel que suggéré par PRANAL Jaiswal:

override open func draw(_ rect: CGRect) { 
     print(#function) 
     let context : CGContext = UIGraphicsGetCurrentContext()! 

     if isEraserSelected { 
      for line in undoArray { 
       //context.beginTransparencyLayer(auxiliaryInfo: nil) 
       context.setLineWidth(line.width) 
       context.addPath(line.path) 
       context.setStrokeColor(UIColor.clear.cgColor) 
       context.setBlendMode(.clear) 
       context.setAlpha(line.opacity) 
       context.setLineCap(.round) 
       context.strokePath() 

      } 
     } else { 
      for line in undoArray { 
       context.setLineWidth(line.width) 
       context.setLineCap(.round) 
       context.addPath(line.path) 
       context.setStrokeColor(line.color.cgColor) 
       context.setBlendMode(.normal) 
       context.setAlpha(line.opacity) 
       context.strokePath() 
      } 

     } 
    } 

I'm still getting the same result. I'd appreciate any more help. 
+1

peut envoyer des messages de code entier u ur classe de dessin comme je l'ai fait dans ma réponse? Je peux mieux comprendre le problème de cette façon ... –

+0

Merci d'avoir regardé à nouveau. J'ai ajouté mon cours de dessin complet maintenant. S'il vous plaît noter, j'utilise des tableaux pour stocker des points à utiliser par mes fonctions annuler/rétablir –

+0

Pourquoi le vote vers le bas s'il vous plaît? –

Répondre

1

je ne pouvais pas regarder exactement à ur le code Mais j'avais fait quelque chose de similaire dans Swift 2.3 il y a quelque temps (je comprends que vous regardez swift 3 mais maintenant c'est la version que j'ai).

Voici à quoi ressemble la classe de dessin.

import Foundation 
import UIKit 
import QuartzCore 

class PRSignatureView: UIView 

{ 

var drawingColor:CGColorRef = UIColor.blackColor().CGColor //Col 
var drawingThickness:CGFloat = 0.5 
var drawingAlpha:CGFloat = 1.0 

var isEraserSelected: Bool 

private var currentPoint:CGPoint? 
private var previousPoint1:CGPoint? 
private var previousPoint2:CGPoint? 

private var path:CGMutablePathRef = CGPathCreateMutable() 

var image:UIImage? 

required init?(coder aDecoder: NSCoder) { 
    //self.backgroundColor = UIColor.clearColor() 
    self.isEraserSelected = false 
    super.init(coder: aDecoder) 
    self.backgroundColor = UIColor.clearColor() 
} 

override func drawRect(rect: CGRect) 
{ 
    self.isEraserSelected ? self.eraseMode() : self.drawingMode() 
} 

private func drawingMode() 
{ 
    if (self.image != nil) 
    { 
     self.image!.drawInRect(self.bounds) 
    } 
    let context:CGContextRef = UIGraphicsGetCurrentContext()! 
    CGContextAddPath(context, path) 
    CGContextSetLineCap(context, CGLineCap.Round) 
    CGContextSetLineWidth(context, self.drawingThickness) 
    CGContextSetStrokeColorWithColor(context, drawingColor) 
    CGContextSetBlendMode(context, CGBlendMode.Normal) 
    CGContextSetAlpha(context, self.drawingAlpha) 
    CGContextStrokePath(context); 
} 

private func eraseMode() 
{ 
    if (self.image != nil) 
    { 
     self.image!.drawInRect(self.bounds) 
    } 
    let context:CGContextRef = UIGraphicsGetCurrentContext()! 
    CGContextSaveGState(context) 
    CGContextAddPath(context, path); 
    CGContextSetLineCap(context, CGLineCap.Round) 
    CGContextSetLineWidth(context, self.drawingThickness) 
    CGContextSetBlendMode(context, CGBlendMode.Clear) 
    CGContextStrokePath(context) 
    CGContextRestoreGState(context) 
} 




private func midPoint (p1:CGPoint, p2:CGPoint)->CGPoint 
{ 
    return CGPointMake((p1.x + p2.x) * 0.5, (p1.y + p2.y) * 0.5) 
} 

private func finishDrawing() 
{ 
    UIGraphicsBeginImageContextWithOptions(self.bounds.size, false, 0.0); 
    drawViewHierarchyInRect(self.bounds, afterScreenUpdates: true) 
    self.image = UIGraphicsGetImageFromCurrentImageContext() 
    UIGraphicsEndImageContext() 
} 

func clearSignature() 
{ 
    path = CGPathCreateMutable() 
    self.image = nil; 
    self.setNeedsDisplay(); 
} 

// MARK: - Touch Delegates 
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) { 
    path = CGPathCreateMutable() 
    let touch = touches.first! 
    previousPoint1 = touch.previousLocationInView(self) 
    currentPoint = touch.locationInView(self) 
} 
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) { 
    let touch = touches.first! 
    previousPoint2 = previousPoint1 
    previousPoint1 = touch.previousLocationInView(self) 
    currentPoint = touch.locationInView(self) 

    let mid1 = midPoint(previousPoint2!, p2: previousPoint1!) 
    let mid2 = midPoint(currentPoint!, p2: previousPoint1!) 

    let subpath:CGMutablePathRef = CGPathCreateMutable() 
    CGPathMoveToPoint(subpath, nil, mid1.x, mid1.y) 
    CGPathAddQuadCurveToPoint(subpath, nil, previousPoint1!.x, previousPoint1!.y, mid2.x, mid2.y) 
    CGPathAddPath(path, nil, subpath); 
    self.setNeedsDisplay() 
} 
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) { 
    self.touchesMoved(touches, withEvent: event) 
    self.finishDrawing() 
} 
override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) { 
    self.touchesMoved(touches!, withEvent: event) 
    self.finishDrawing() 
} 

} 

Source Code for test app I created using the above code

Modifier: Conversion de quelques lignes de code à swift 3 comme l'a demandé

subpath.move(to: CGPoint(x: mid1.x, y: mid1.y)) 
subpath.addQuadCurve(to:CGPoint(x: mid2.x, y: mid2.y) , control: CGPoint(x: previousPoint1!.x, y: previousPoint1!.y)) 
path.addPath(subpath) 

Edit: En réponse à la question mise à jour

Voici la mise à jour Classe de dessin qui doit résoudre le problème à coup sûr. https://drive.google.com/file/d/0B5nqEBSJjCriTU5oRXd5c2hRV28/view?usp=sharing

Questions examinées:

  1. Line Struct n'a pas tenu le type d'outil associé. Chaque fois que setNeedsDislpay() est appelée, vous redessinez tous les objets dans pathArray et tous les objets étaient redessinés avec l'outil sélectionné. J'ai ajouté une nouvelle variable associatedTool pour résoudre le problème. L'utilisation de la fonction beginTransparencyLayer permet de définir le mode de fusion sur kCGBlendModeNormal. Comme cela était courant pour tous les cas liés au type d'outil, le mode était réglé sur normal. J'ai enlevé ces deux lignes

//context.beginTransparencyLayer(auxiliaryInfo: néant)

//context.endTransparencyLayer()

+0

Merci! Je vais vérifier cela dès que possible. J'apprécie beaucoup votre aide. –

+0

J'essaie de convertir votre code de dessin en Swift3 .. Je suis accroché avec la fonction touchesMoved. Plus précisément: CGPathMoveToPoint (subpath, nil, mid1.x, mid1.y). Ils ne compilent pas .. Des idées? Merci encore \t \t CGPathAddQuadCurveToPoint (sous-chemin, nul, previousPoint1 .x, .y previousPoint1, mid2.x, mid2.y!) \ N CGPathAddPath (chemin, nul, sous-chemin); \ n –

+0

S'il vous plaît vérifier la réponse modifiée . Devrait travailler, ne l'a pas testé cependant! –

0

Essayez cela, il n'a pas d'erreur lors de l'effacement et cela peut être nous pour dessiner et effacer votre écran. Vous pouvez même augmenter ou diminuer la taille du crayon et de l'effaceur. vous pouvez également changer de couleur en conséquence.

espère que cela helpfull pour u .....

importation UIKit

class DrawingView: UIView { 

var lineColor:CGColor = UIColor.black.cgColor 
var lineWidth:CGFloat = 5 
var drawingAlpha:CGFloat = 1.0 

var isEraserSelected: Bool 

private var currentPoint:CGPoint? 
private var previousPoint1:CGPoint? 
private var previousPoint2:CGPoint? 

private var path:CGMutablePath = CGMutablePath() 

var image:UIImage? 

required init?(coder aDecoder: NSCoder) { 
    //self.backgroundColor = UIColor.clearColor() 
    self.isEraserSelected = false 
    super.init(coder: aDecoder) 
    self.backgroundColor = UIColor.clear 
} 

override func draw(_ rect: CGRect) 
{ 
    self.isEraserSelected ? self.eraseMode() : self.drawingMode() 
} 

private func drawingMode() 
{ 
    if (self.image != nil) 
    { 
     self.image!.draw(in: self.bounds) 
    } 
    let context:CGContext = UIGraphicsGetCurrentContext()! 
    context.addPath(path) 
    context.setLineCap(CGLineCap.round) 
    context.setLineWidth(self.lineWidth) 
    context.setStrokeColor(lineColor) 
    context.setBlendMode(CGBlendMode.normal) 
    context.setAlpha(self.drawingAlpha) 
    context.strokePath(); 
} 

private func eraseMode() 
{ 
    if (self.image != nil) 
    { 
     self.image!.draw(in: self.bounds) 
    } 
    let context:CGContext = UIGraphicsGetCurrentContext()! 
    context.saveGState() 
    context.addPath(path); 
    context.setLineCap(CGLineCap.round) 
    context.setLineWidth(self.lineWidth) 
    context.setBlendMode(CGBlendMode.clear) 
    context.strokePath() 
    context.restoreGState() 
} 

private func midPoint (p1:CGPoint, p2:CGPoint)->CGPoint 
{ 
    return CGPoint(x: (p1.x + p2.x) * 0.5, y: (p1.y + p2.y) * 0.5); 
} 

private func finishDrawing() 
{ 
    UIGraphicsBeginImageContextWithOptions(self.bounds.size, false, 0.0); 
    drawHierarchy(in: self.bounds, afterScreenUpdates: true) 
    self.image = UIGraphicsGetImageFromCurrentImageContext() 
    UIGraphicsEndImageContext() 
} 

func clearSignature() 
{ 
    path = CGMutablePath() 
    self.image = nil; 
    self.setNeedsDisplay(); 
} 

// MARK: - Touch Delegates 
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { 
    path = CGMutablePath() 
    let touch = touches.first! 
    previousPoint1 = touch.previousLocation(in: self) 
    currentPoint = touch.location(in: self) 
} 
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) { 
    let touch = touches.first! 
    previousPoint2 = previousPoint1 
    previousPoint1 = touch.previousLocation(in: self) 
    currentPoint = touch.location(in: self) 

    let mid1 = midPoint(p1: previousPoint2!, p2: previousPoint1!) 
    let mid2 = midPoint(p1: currentPoint!, p2: previousPoint1!) 

    let subpath:CGMutablePath = CGMutablePath() 
    subpath.move(to: CGPoint(x: mid1.x, y: mid1.y), transform: .identity) 
    subpath.addQuadCurve(to: CGPoint(x: mid2.x, y: mid2.y), control: CGPoint(x: (previousPoint1?.x)!, y: (previousPoint1?.y)!)) 
    path.addPath(subpath, transform: .identity) 

    self.setNeedsDisplay() 
} 
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { 
    self.touchesMoved(touches, with: event) 
    self.finishDrawing() 
} 
override func touchesCancelled(_ touches: Set<UITouch>?, with event: UIEvent?) { 
    self.touchesMoved(touches!, with: event) 
    self.finishDrawing() 
} 
} 
+3

pour être vraiment utile, vous devriez non seulement poster du code mais aussi des explications sur ce que vous avez fait/pourquoi vous l'avez fait etc. – jps

+0

ok merci pour l'info @jps –