|
|
@ -173,6 +173,7 @@ public class ImageEditorCanvasView: UIView {
|
|
|
|
contentLayerMap.removeAll()
|
|
|
|
contentLayerMap.removeAll()
|
|
|
|
|
|
|
|
|
|
|
|
let viewSize = clipView.bounds.size
|
|
|
|
let viewSize = clipView.bounds.size
|
|
|
|
|
|
|
|
let transform = model.currentTransform()
|
|
|
|
if viewSize.width > 0,
|
|
|
|
if viewSize.width > 0,
|
|
|
|
viewSize.height > 0 {
|
|
|
|
viewSize.height > 0 {
|
|
|
|
|
|
|
|
|
|
|
@ -183,6 +184,7 @@ public class ImageEditorCanvasView: UIView {
|
|
|
|
for item in model.items() {
|
|
|
|
for item in model.items() {
|
|
|
|
guard let layer = ImageEditorCanvasView.layerForItem(item: item,
|
|
|
|
guard let layer = ImageEditorCanvasView.layerForItem(item: item,
|
|
|
|
model: model,
|
|
|
|
model: model,
|
|
|
|
|
|
|
|
transform: transform,
|
|
|
|
viewSize: viewSize) else {
|
|
|
|
viewSize: viewSize) else {
|
|
|
|
continue
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -217,6 +219,7 @@ public class ImageEditorCanvasView: UIView {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let viewSize = clipView.bounds.size
|
|
|
|
let viewSize = clipView.bounds.size
|
|
|
|
|
|
|
|
let transform = model.currentTransform()
|
|
|
|
if viewSize.width > 0,
|
|
|
|
if viewSize.width > 0,
|
|
|
|
viewSize.height > 0 {
|
|
|
|
viewSize.height > 0 {
|
|
|
|
|
|
|
|
|
|
|
@ -234,6 +237,7 @@ public class ImageEditorCanvasView: UIView {
|
|
|
|
// Item was inserted or updated.
|
|
|
|
// Item was inserted or updated.
|
|
|
|
guard let layer = ImageEditorCanvasView.layerForItem(item: item,
|
|
|
|
guard let layer = ImageEditorCanvasView.layerForItem(item: item,
|
|
|
|
model: model,
|
|
|
|
model: model,
|
|
|
|
|
|
|
|
transform: transform,
|
|
|
|
viewSize: viewSize) else {
|
|
|
|
viewSize: viewSize) else {
|
|
|
|
continue
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -320,6 +324,7 @@ public class ImageEditorCanvasView: UIView {
|
|
|
|
|
|
|
|
|
|
|
|
private class func layerForItem(item: ImageEditorItem,
|
|
|
|
private class func layerForItem(item: ImageEditorItem,
|
|
|
|
model: ImageEditorModel,
|
|
|
|
model: ImageEditorModel,
|
|
|
|
|
|
|
|
transform: ImageEditorTransform,
|
|
|
|
viewSize: CGSize) -> CALayer? {
|
|
|
|
viewSize: CGSize) -> CALayer? {
|
|
|
|
AssertIsOnMainThread()
|
|
|
|
AssertIsOnMainThread()
|
|
|
|
|
|
|
|
|
|
|
@ -332,7 +337,10 @@ public class ImageEditorCanvasView: UIView {
|
|
|
|
owsFailDebug("Item has unexpected type: \(type(of: item)).")
|
|
|
|
owsFailDebug("Item has unexpected type: \(type(of: item)).")
|
|
|
|
return nil
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return strokeLayerForItem(item: strokeItem, viewSize: viewSize)
|
|
|
|
return strokeLayerForItem(item: strokeItem,
|
|
|
|
|
|
|
|
model: model,
|
|
|
|
|
|
|
|
transform: transform,
|
|
|
|
|
|
|
|
viewSize: viewSize)
|
|
|
|
case .text:
|
|
|
|
case .text:
|
|
|
|
guard let textItem = item as? ImageEditorTextItem else {
|
|
|
|
guard let textItem = item as? ImageEditorTextItem else {
|
|
|
|
owsFailDebug("Item has unexpected type: \(type(of: item)).")
|
|
|
|
owsFailDebug("Item has unexpected type: \(type(of: item)).")
|
|
|
@ -340,11 +348,14 @@ public class ImageEditorCanvasView: UIView {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return textLayerForItem(item: textItem,
|
|
|
|
return textLayerForItem(item: textItem,
|
|
|
|
model: model,
|
|
|
|
model: model,
|
|
|
|
|
|
|
|
transform: transform,
|
|
|
|
viewSize: viewSize)
|
|
|
|
viewSize: viewSize)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private class func strokeLayerForItem(item: ImageEditorStrokeItem,
|
|
|
|
private class func strokeLayerForItem(item: ImageEditorStrokeItem,
|
|
|
|
|
|
|
|
model: ImageEditorModel,
|
|
|
|
|
|
|
|
transform: ImageEditorTransform,
|
|
|
|
viewSize: CGSize) -> CALayer? {
|
|
|
|
viewSize: CGSize) -> CALayer? {
|
|
|
|
AssertIsOnMainThread()
|
|
|
|
AssertIsOnMainThread()
|
|
|
|
|
|
|
|
|
|
|
@ -361,9 +372,9 @@ public class ImageEditorCanvasView: UIView {
|
|
|
|
shapeLayer.strokeColor = item.color.cgColor
|
|
|
|
shapeLayer.strokeColor = item.color.cgColor
|
|
|
|
shapeLayer.frame = CGRect(origin: .zero, size: viewSize)
|
|
|
|
shapeLayer.frame = CGRect(origin: .zero, size: viewSize)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let imageFrame = ImageEditorCanvasView.imageFrame(forViewSize: viewSize, imageSize: model.srcImageSizePixels, transform: transform)
|
|
|
|
let transformSampleToPoint = { (unitSample: CGPoint) -> CGPoint in
|
|
|
|
let transformSampleToPoint = { (unitSample: CGPoint) -> CGPoint in
|
|
|
|
return CGPoint(x: viewSize.width * unitSample.x,
|
|
|
|
return unitSample.fromUnitCoordinates(viewBounds: imageFrame)
|
|
|
|
y: viewSize.height * unitSample.y)
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Use bezier curves to smooth stroke.
|
|
|
|
// Use bezier curves to smooth stroke.
|
|
|
@ -436,11 +447,11 @@ public class ImageEditorCanvasView: UIView {
|
|
|
|
|
|
|
|
|
|
|
|
private class func textLayerForItem(item: ImageEditorTextItem,
|
|
|
|
private class func textLayerForItem(item: ImageEditorTextItem,
|
|
|
|
model: ImageEditorModel,
|
|
|
|
model: ImageEditorModel,
|
|
|
|
|
|
|
|
transform: ImageEditorTransform,
|
|
|
|
viewSize: CGSize) -> CALayer? {
|
|
|
|
viewSize: CGSize) -> CALayer? {
|
|
|
|
AssertIsOnMainThread()
|
|
|
|
AssertIsOnMainThread()
|
|
|
|
|
|
|
|
|
|
|
|
let imageFrame = self.imageFrame(forViewSize: viewSize, imageSize: model.srcImageSizePixels,
|
|
|
|
let imageFrame = ImageEditorCanvasView.imageFrame(forViewSize: viewSize, imageSize: model.srcImageSizePixels, transform: transform)
|
|
|
|
transform: model.currentTransform())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// We need to adjust the font size to reflect the current output scale,
|
|
|
|
// We need to adjust the font size to reflect the current output scale,
|
|
|
|
// using the image width as reference.
|
|
|
|
// using the image width as reference.
|
|
|
@ -476,8 +487,7 @@ public class ImageEditorCanvasView: UIView {
|
|
|
|
.font: item.font.withSize(fontSize)
|
|
|
|
.font: item.font.withSize(fontSize)
|
|
|
|
],
|
|
|
|
],
|
|
|
|
context: nil)
|
|
|
|
context: nil)
|
|
|
|
let center = CGPoint(x: viewSize.width * item.unitCenter.x,
|
|
|
|
let center = item.unitCenter.fromUnitCoordinates(viewBounds: imageFrame)
|
|
|
|
y: viewSize.height * item.unitCenter.y)
|
|
|
|
|
|
|
|
let layerSize = CGSizeCeil(textBounds.size)
|
|
|
|
let layerSize = CGSizeCeil(textBounds.size)
|
|
|
|
layer.frame = CGRect(origin: CGPoint(x: center.x - layerSize.width * 0.5,
|
|
|
|
layer.frame = CGRect(origin: CGPoint(x: center.x - layerSize.width * 0.5,
|
|
|
|
y: center.y - layerSize.height * 0.5),
|
|
|
|
y: center.y - layerSize.height * 0.5),
|
|
|
@ -535,24 +545,24 @@ public class ImageEditorCanvasView: UIView {
|
|
|
|
transform: ImageEditorTransform) -> CGPoint {
|
|
|
|
transform: ImageEditorTransform) -> CGPoint {
|
|
|
|
let locationInView = gestureRecognizer.location(in: view)
|
|
|
|
let locationInView = gestureRecognizer.location(in: view)
|
|
|
|
return locationUnit(forLocationInView: locationInView,
|
|
|
|
return locationUnit(forLocationInView: locationInView,
|
|
|
|
viewSize: view.bounds.size,
|
|
|
|
viewBounds: view.bounds,
|
|
|
|
transform: transform)
|
|
|
|
transform: transform)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public func locationUnit(forLocationInView locationInView: CGPoint,
|
|
|
|
public func locationUnit(forLocationInView locationInView: CGPoint,
|
|
|
|
transform: ImageEditorTransform) -> CGPoint {
|
|
|
|
transform: ImageEditorTransform) -> CGPoint {
|
|
|
|
let viewSize = self.clipView.bounds.size
|
|
|
|
let viewBounds = self.clipView.bounds
|
|
|
|
return ImageEditorCanvasView.locationUnit(forLocationInView: locationInView,
|
|
|
|
return ImageEditorCanvasView.locationUnit(forLocationInView: locationInView,
|
|
|
|
viewSize: viewSize,
|
|
|
|
viewBounds: viewBounds,
|
|
|
|
transform: transform)
|
|
|
|
transform: transform)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public class func locationUnit(forLocationInView locationInView: CGPoint,
|
|
|
|
public class func locationUnit(forLocationInView locationInView: CGPoint,
|
|
|
|
viewSize: CGSize,
|
|
|
|
viewBounds: CGRect,
|
|
|
|
transform: ImageEditorTransform) -> CGPoint {
|
|
|
|
transform: ImageEditorTransform) -> CGPoint {
|
|
|
|
let affineTransformStart = transform.affineTransform(viewSize: viewSize)
|
|
|
|
let affineTransformStart = transform.affineTransform(viewSize: viewBounds.size)
|
|
|
|
let locationInContent = locationInView.applyingInverse(affineTransformStart)
|
|
|
|
let locationInContent = locationInView.minus(viewBounds.center).applyingInverse(affineTransformStart).plus(viewBounds.center)
|
|
|
|
let locationUnit = locationInContent.toUnitCoordinates(viewSize: viewSize, shouldClamp: false)
|
|
|
|
let locationUnit = locationInContent.toUnitCoordinates(viewSize: viewBounds.size, shouldClamp: false)
|
|
|
|
return locationUnit
|
|
|
|
return locationUnit
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -608,6 +618,7 @@ public class ImageEditorCanvasView: UIView {
|
|
|
|
for item in model.items() {
|
|
|
|
for item in model.items() {
|
|
|
|
guard let layer = layerForItem(item: item,
|
|
|
|
guard let layer = layerForItem(item: item,
|
|
|
|
model: model,
|
|
|
|
model: model,
|
|
|
|
|
|
|
|
transform: transform,
|
|
|
|
viewSize: viewSize) else {
|
|
|
|
viewSize: viewSize) else {
|
|
|
|
owsFailDebug("Couldn't create layer for item.")
|
|
|
|
owsFailDebug("Couldn't create layer for item.")
|
|
|
|
continue
|
|
|
|
continue
|
|
|
|