Работа с приложением, которое берет фоновое изображение из рулона камеры, а затем берет 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
@ Крис делает код в моем отредактированном ответе, который помогает вам решить проблему? Если да, можете ли вы принять ответ, а если нет, можете ли вы рассказать мне больше о продолжающейся трудности? –