2016-12-11 23 views
-1

CoreGraphicsで消しゴ​​ムツールを作成することには、多くの質問があります。私は "pixilated"と一致するものを見つけることができません。スウィフト - 私の消しゴムツールはなぜピクセル化されますか

ここに状況があります。私は簡単な描画プロジェクトで遊んでいます。ペンツールはうまく動作します。消しゴムツールは恐ろしいようにピクセル化されています。ここで私が何を意味するかのスクリーンショットだ:

// 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 
    } 
} 

UPDATE:

私は、各消しゴムのタッチがあることがわかり

enter image description here

ここで描画コードは、私が(更新)使用しています平方。より詳細に示すために、第2の画像をご覧ください。

enter image description here

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

uはウル描画クラスのコード全体を投稿することができますか?私はそのような問題をよりよく理解することができます... –

+0

もう一度見ていただきありがとうございます。私は完全な描画クラスを今追加しました。注意してください、私は私の元に戻す/やり直し機能で使用するためにポイントを格納するために配列を使用しています –

+0

なぜ下の投票をしてください? –

答えて

1

私は正確にウルのコードを見ませんでした。しかし、私は持っていました私はSwift 3を見ていると分かっていますが、今はこれが私の持っているバージョンです。

ここで、描画クラスの仕組みを示します。

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

編集:ここでは、更新の質問

に応じて更新されます。要求さ

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) 

編集は次のように迅速3に数行のコードを変換します問題を確実に解決しなければならない抽象クラス。 https://drive.google.com/file/d/0B5nqEBSJjCriTU5oRXd5c2hRV28/view?usp=sharing

の問題に対処:

  1. Line構造体は、関連するツールの種類を保有していませんでした。 setNeedsDislpay()が呼び出されると、pathArrayにすべてのオブジェクトが再描画され、現在選択されているすべてのオブジェクトが再描画されていました。問題を解決するために新しい変数associatedToolを追加しました。
  2. ファンクションbeginTransparencyLayerを使用すると、ブレンドモードがkCGBlendModeNormalに設定されます。これはツールタイプに関連するすべてのケースで共通であったため、これはモードを正常に設定していました。私はこの2行

//context.beginTransparencyLayer(auxiliaryInfo削除されました:ゼロ)

//context.endTransparencyLayer()

+0

ありがとう!私はこれをできるだけ早くチェックします。私はあなたの助けに多く感謝します。 –

+0

私はあなたの描画コードをSwift3に変換しようとしています。私はtouchesMoved関数でハングアップしています。特に:CGPathMoveToPoint(subpath、nil、mid1.x、mid1.y)。彼らはコンパイルされません..任意のアイデア?おかげで再び \t \t CGPathAddQuadCurveToPoint(サブパス、ゼロ、previousPoint1 .X、previousPoint1 .Y、mid2.x、mid2.y!!)\ nは CGPathAddPath(パス、ゼロ、サブパス); \ nは –

+0

は、編集した答えを確認してください。動作しなければならない、それをテストしていない! –

0

を消去しながら、それは誤りがない、これを試してみて、画面を消去してクリアすることができます。鉛筆と消しゴムの大きさを増減することもできます。それに応じて色も変わるかもしれません。これはuのための参考になっている

希望私は私の答えで行ったように.....

輸入の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

本当に役に立つと思うだけでなく、コードを投稿するだけでなく、あなたがやったことについていくつかの説明をする必要があります。 – jps

+0

info @jps –

関連する問題