使用從相機膠捲獲取背景圖像然後拍攝PNG進行疊加的應用程序,操縱PNG(捏合,縮放,旋轉等),然後返回合成圖像下面的視圖控制器。獲取CGImage以適應Swift方面
無論我嘗試什麼,我都會想出如何讓代碼適合背景圖像。下面代碼中的疊加層(topLayerImage.image)至少在轉換時保持其方面。不過,背景圖像正在被迫成爲一種形狀。例如,UIImageView在默認情況下是手機上縱向視圖的垂直圖像,並且無論原始照片的原始高寬比如何,所得圖像都以該形狀的形式返回。
我已經看到了一些Objective-C方法來處理這個問題,儘管我整個下午都沒有運氣。有人可能知道我要去哪裏錯了嗎?這裏是我的代碼:
import UIKit
class TwoLayerViewController: UIViewController {
@IBOutlet weak var ghostHolderView: UIView!
@IBOutlet weak var bottomLayerImage: UIImageView!
@IBOutlet weak var topLayerImage: UIImageView!
@IBOutlet weak var amountSlider: UISlider!
@IBOutlet weak var nextPageButton: UIButton!
var originalPhoto: UIImage?
var chosenGhostPhoto: UIImage?
var newImage:UIImage?
var newBGImage:UIImage?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
bottomLayerImage.image = originalPhoto
bottomLayerImage.contentMode = UIViewContentMode.ScaleAspectFit
topLayerImage.image = chosenGhostPhoto
topLayerImage.alpha = 1.0
topLayerImage.contentMode = UIViewContentMode.ScaleAspectFit
}
@IBAction func handlePan(recognizer:UIPanGestureRecognizer) {
let translation = recognizer.translationInView(self.view)
if let view = recognizer.view {
view.center = CGPoint(x:view.center.x + translation.x,
y:view.center.y + translation.y)
}
recognizer.setTranslation(CGPointZero, inView: self.view)
}
@IBAction func handlePinch(recognizer : UIPinchGestureRecognizer) {
if let view = recognizer.view {
view.transform = CGAffineTransformScale(view.transform,
recognizer.scale, recognizer.scale)
recognizer.scale = 1
}
}
@IBAction func handleRotate(recognizer : UIRotationGestureRecognizer) {
if let view = recognizer.view {
view.transform = CGAffineTransformRotate(view.transform, recognizer.rotation)
var transform:CGAffineTransform = view.transform
var angle:CGFloat = atan2(transform.b, transform.a)
println(angle)
}
}
@IBAction func sliderChangeAmount(sender: UISlider) {
// let sliderValue = CGFloat(sender.value)
//
// topLayerImage.alpha = sliderValue
}
@IBAction func combineImagesButton(sender: AnyObject) {
let originalWidth = originalPhoto!.size.width
let originalHeight = originalPhoto!.size.height
let finalWidth = bottomLayerImage.frame.size.width
let finalHeight = bottomLayerImage.frame.size.height
let finalSize : CGSize = CGSizeMake(finalWidth, finalHeight)
UIGraphicsBeginImageContext(finalSize)
let size = CGSizeApplyAffineTransform(originalPhoto!.size, CGAffineTransformMakeScale(finalWidth/originalWidth, finalHeight/originalHeight))
originalPhoto!.drawInRect(CGRect(origin: CGPointZero, size: size))
// originalPhoto!.drawInRect(bottomLayerImage.frame)
let imgCon = UIGraphicsGetCurrentContext()
CGContextTranslateCTM(imgCon, 0.5 * finalSize.width, 0.5 * finalSize.height) ;
CGContextRotateCTM(imgCon, atan2(topLayerImage.transform.b, topLayerImage.transform.a));
chosenGhostPhoto!.drawInRect(topLayerImage.frame, blendMode: kCGBlendModeNormal, alpha:0.8)
newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
println(newImage)
println(finalSize)
println(originalPhoto!.size.width, originalPhoto!.size.height)
}
func getBoundingRectAfterRotation(rect: CGRect, angle: Float) -> CGRect {
let newWidth : Float = Float(rect.size.width) * abs(cosf(angle)) + Float(rect.size.height) * fabs(sinf(angle))
let newHeight : Float = Float(rect.size.height) * fabs(cosf(angle)) + Float(rect.size.width) * fabs(sinf(angle))
let newX : Float = Float(rect.origin.x) + ((Float(rect.size.width) - newWidth)/2);
let newY : Float = Float(rect.origin.y) + ((Float(rect.size.height) - newHeight)/2);
let rotatedRect : CGRect = CGRectMake(CGFloat(newX), CGFloat(newY), CGFloat(newWidth), CGFloat(newHeight))
return rotatedRect
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let vc = segue.destinationViewController as? CombinedLayerViewController {
vc.fullImage = self.newImage
}
}
}
UPDATE:提摩太的建議,有一些小的調整,製作的背景問題,但我有與覆蓋麻煩,顯然是在規模,我認爲,原點。這是我的草率代碼:
import UIKit
class TwoLayerViewController: UIViewController {
@IBOutlet weak var ghostHolderView: UIView!
@IBOutlet weak var bottomLayerImage: UIImageView!
@IBOutlet weak var topLayerImage: UIImageView!
@IBOutlet weak var amountSlider: UISlider!
@IBOutlet weak var nextPageButton: UIButton!
var originalPhoto: UIImage?
var chosenGhostPhoto: UIImage?
var newImage:UIImage?
var newBGImage:UIImage?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
bottomLayerImage.image = originalPhoto
bottomLayerImage.contentMode = UIViewContentMode.ScaleAspectFit
topLayerImage.image = chosenGhostPhoto
// topLayerImage.alpha = 1.0
// topLayerImage.contentMode = UIViewContentMode.ScaleAspectFit
}
@IBAction func handlePan(recognizer:UIPanGestureRecognizer) {
let translation = recognizer.translationInView(self.view)
if let view = recognizer.view {
view.center = CGPoint(x:view.center.x + translation.x,
y:view.center.y + translation.y)
}
recognizer.setTranslation(CGPointZero, inView: self.view)
}
@IBAction func handlePinch(recognizer : UIPinchGestureRecognizer) {
if let view = recognizer.view {
view.transform = CGAffineTransformScale(view.transform,
recognizer.scale, recognizer.scale)
recognizer.scale = 1
}
}
@IBAction func handleRotate(recognizer : UIRotationGestureRecognizer) {
if let view = recognizer.view {
view.transform = CGAffineTransformRotate(view.transform, recognizer.rotation)
var transform:CGAffineTransform = view.transform
var angle:CGFloat = atan2(transform.b, transform.a)
println(angle)
}
}
@IBAction func sliderChangeAmount(sender: UISlider) {
// let sliderValue = CGFloat(sender.value)
//
// topLayerImage.alpha = sliderValue
}
@IBAction func combineImagesButton(sender: AnyObject) {
var originalPhotoFrame: CGRect?
var backgroundLayerFrame: CGRect?
var ghostOriginalPhotoFrame: CGRect?
var ghostBackgroundLayerFrame: CGRect?
if bottomLayerImage.image!.size.width > bottomLayerImage.image!.size.height {
originalPhotoFrame = CGRect(x: 0,y: 0, width: bottomLayerImage.image!.size.width, height: bottomLayerImage.image!.size.height)
backgroundLayerFrame = CGRect(x: 0, y: 0, width: bottomLayerImage.frame.size.width, height: bottomLayerImage.frame.size.height)
} else {
originalPhotoFrame = CGRect(x: 0,y: 0, width: bottomLayerImage.frame.size.width, height: bottomLayerImage.frame.height)
backgroundLayerFrame = CGRect(x: 0, y: 0, width: bottomLayerImage.frame.size.width, height: bottomLayerImage.frame.size.height)
}
// Now figure out whether the ScaleAspectFit was horizontally or vertically bound.
let horizScale = backgroundLayerFrame!.width/originalPhotoFrame!.width
let vertScale = backgroundLayerFrame!.height/originalPhotoFrame!.height
let myScale = min(horizScale, vertScale)
// So we don't need to do each of these calculations on a separate line, but for ease of explanation…
// Now we can calculate the size to scale originalPhoto
let scaledSize = CGSize(width: originalPhotoFrame!.size.width * myScale,
height: originalPhotoFrame!.size.height * myScale)
// And now we need to center originalPhoto inside backgroundLayerFrame
let scaledOrigin = CGPoint(x: (backgroundLayerFrame!.width - scaledSize.width)/2,
y: (backgroundLayerFrame!.height - scaledSize.height)/2)
// Put it all together
let scaledPhotoRect = CGRect(origin: scaledOrigin, size: scaledSize)
//////
if topLayerImage.image!.size.width > topLayerImage.image!.size.height {
ghostOriginalPhotoFrame = CGRect(x: 0,y: 0, width: topLayerImage.image!.size.width, height: topLayerImage.image!.size.height)
ghostBackgroundLayerFrame = CGRect(x: topLayerImage.frame.origin.x, y: topLayerImage.frame.origin.y, width: topLayerImage.frame.size.width, height: topLayerImage.frame.size.height)
} else {
ghostOriginalPhotoFrame = CGRect(x: topLayerImage.frame.origin.x,y: topLayerImage.frame.origin.y, width: topLayerImage.frame.size.width, height: topLayerImage.frame.height)
ghostBackgroundLayerFrame = CGRect(x: topLayerImage.frame.origin.x, y: topLayerImage.frame.origin.y, width: topLayerImage.frame.size.width, height: topLayerImage.frame.size.height)
}
// Now figure out whether the ScaleAspectFit was horizontally or vertically bound.
let ghostHorizScale = ghostBackgroundLayerFrame!.width/ghostOriginalPhotoFrame!.width
let ghostVertScale = ghostBackgroundLayerFrame!.height/ghostOriginalPhotoFrame!.height
let ghostMyScale = min(ghostHorizScale, ghostVertScale)
// So we don't need to do each of these calculations on a separate line, but for ease of explanation…
// Now we can calculate the size to scale originalPhoto
let ghostScaledSize = CGSize(width: ghostOriginalPhotoFrame!.size.width * ghostMyScale,
height: ghostOriginalPhotoFrame!.size.height * ghostMyScale)
// And now we need to center originalPhoto inside backgroundLayerFrame
let ghostScaledOrigin = CGPoint(x: (ghostBackgroundLayerFrame!.width - ghostScaledSize.width)/2,
y: (ghostBackgroundLayerFrame!.height - ghostScaledSize.height)/2)
// Put it all together
let ghostScaledPhotoRect = CGRect(origin: ghostScaledOrigin, size: ghostScaledSize)
//////
// UIGraphicsBeginImageContext(scaledSize)
UIGraphicsBeginImageContextWithOptions(scaledSize, false, 0)
originalPhoto!.drawInRect(CGRect(origin: CGPointZero, size: scaledSize))
let imgCon = UIGraphicsGetCurrentContext()
// CGContextTranslateCTM(imgCon, 0.5 * finalSize.width, 0.5 * finalSize.height) ;
CGContextRotateCTM(imgCon, atan2(topLayerImage.transform.b, topLayerImage.transform.a));
// chosenGhostPhoto!.drawInRect(CGRect(origin: topLayerImage.frame.origin, size: ghostScaledSize))
chosenGhostPhoto!.drawInRect(ghostScaledPhotoRect, blendMode: kCGBlendModeNormal, alpha: 0.8)
// chosenGhostPhoto!.drawInRect(CGRect(origin: chosenGhostPhoto, size: ghostScaledSize), blendMode: kCGBlendModeNormal, alpha:0.8)
newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
println(newImage)
// println(finalSize)
println(originalPhoto!.size.width, originalPhoto!.size.height)
}
// func getBoundingRectAfterRotation(rect: CGRect, angle: Float) -> CGRect {
// let newWidth : Float = Float(rect.size.width) * abs(cosf(angle)) + Float(rect.size.height) * fabs(sinf(angle))
//
// let newHeight : Float = Float(rect.size.height) * fabs(cosf(angle)) + Float(rect.size.width) * fabs(sinf(angle))
//
// let newX : Float = Float(rect.origin.x) + ((Float(rect.size.width) - newWidth)/2);
// let newY : Float = Float(rect.origin.y) + ((Float(rect.size.height) - newHeight)/2);
// let rotatedRect : CGRect = CGRectMake(CGFloat(newX), CGFloat(newY), CGFloat(newWidth), CGFloat(newHeight))
// return rotatedRect
// }
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let vc = segue.destinationViewController as? CombinedLayerViewController {
vc.fullImage = self.newImage
}
}
當然,下面是一些截圖。首先,你可以看到有人可能會調整topLayerImage(幽靈),bottomLayerImage只是從相機膠捲中選擇的一個。 第二個圖像是結果。第三個是重新定位的幽靈照片,所以你可以更好地看到它。看起來該圖像的高寬比保持不變,這不能說是背景圖像。 http://imgur.com/7ymXJG7,6OJdwVW,jD9byza http://imgur.com/7ymXJG7,6OJdwVW,jD9byza#1 http://imgur.com/7ymXJG7,6OJdwVW,jD9byza#2 – Chris
細算更密切地說,我立場糾正:鬼影似乎扭曲了一些。 – Chris
@Chris在我編輯的答案中執行代碼可以幫助您解決問題?如果是這樣,你能接受答案,如果沒有,你能告訴我更多關於持續的困難嗎? –