1
0

DrawViewController.swift 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. //
  2. // DrawViewController.swift
  3. // AIPaint
  4. //
  5. // Created by Fengyu He on 2022/11/29.
  6. //
  7. import UIKit
  8. import Photos
  9. import SnapKit
  10. import SwiftyJSON
  11. import SwiftUI
  12. import CoreData
  13. import Alamofire
  14. class DrawViewController: UIViewController, UIScrollViewDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
  15. var drawModeView: UIScrollView!
  16. lazy var generateView: UIView = {
  17. let view = UIView()
  18. view.backgroundColor = UIColor(red: 48/255, green: 155/255, blue: 255/255, alpha: 1.0)
  19. view.layer.cornerRadius = 14.0
  20. return view
  21. }()
  22. lazy var promptTextField: UITextField = {
  23. let textField = UITextField()
  24. textField.placeholder = "请输入你的作品的组成元素,以空格分割。"
  25. textField.backgroundColor = .white
  26. textField.layer.cornerRadius = 14.0
  27. textField.returnKeyType = .done
  28. return textField
  29. }()
  30. lazy var negativePromptTextField: UITextField = {
  31. let textField = UITextField()
  32. textField.placeholder = "请输入你不想在作品中看到的元素,以空格分割。"
  33. textField.backgroundColor = .white
  34. textField.layer.cornerRadius = 14.0
  35. textField.returnKeyType = .done
  36. return textField
  37. }()
  38. lazy var generateButton: UIButton = {
  39. let button = UIButton()
  40. button.layer.backgroundColor = UIColor.black.cgColor
  41. button.addTarget(self, action: #selector(generateAction), for: .touchUpInside)
  42. button.setTitle("生成图片", for: .normal)
  43. button.tintColor = .white
  44. button.isUserInteractionEnabled = true
  45. button.layer.cornerRadius = 14.0
  46. return button
  47. }()
  48. var longPress: UILongPressGestureRecognizer?
  49. lazy var generateImage: UIImageView = {
  50. let imageView = UIImageView()
  51. imageView.layer.borderWidth = 1
  52. imageView.layer.borderColor = UIColor.black.cgColor
  53. imageView.isUserInteractionEnabled = true
  54. return imageView
  55. }()
  56. lazy var remindText: UILabel = {
  57. var label = UILabel()
  58. label.text = "长按图片进行保存"
  59. label.textColor = .systemGray5
  60. label.textAlignment = .center
  61. return label
  62. }()
  63. lazy var imageUploadView: UIView = {
  64. var view = UIView()
  65. view.layer.borderWidth = 1
  66. view.layer.borderColor = UIColor.black.cgColor
  67. return view
  68. }()
  69. lazy var pic2PicLabel: UILabel = {
  70. var label = UILabel()
  71. label.text = "图片动漫化"
  72. return label
  73. }()
  74. lazy var uploadImage: UIImageView = {
  75. var imageView = UIImageView()
  76. let singleGusture = UITapGestureRecognizer(target: self, action: #selector(pickPhotoFromAlbum))
  77. imageView.addGestureRecognizer(singleGusture)
  78. imageView.isUserInteractionEnabled = true
  79. return imageView
  80. }()
  81. var prompt = ""
  82. var tranPrompt = ""
  83. var negativePrompt = ""
  84. var tranNegativePrompt = ""
  85. var sessionHash = ""
  86. var delegate: AppDelegate?
  87. var context: NSManagedObjectContext?
  88. var painting: Painting?
  89. let alertController = UIAlertController(title: "保存成功!", message: nil, preferredStyle: .alert)
  90. let userDefaults = UserDefaults.standard
  91. var pickedImage: UIImage?
  92. override func viewDidLoad() {
  93. super.viewDidLoad()
  94. drawModeView = UIScrollView()
  95. drawModeView.delegate = self
  96. drawModeView.showsVerticalScrollIndicator = true
  97. drawModeView.isScrollEnabled = true
  98. self.view.addSubview(drawModeView)
  99. drawModeView.snp.makeConstraints { (make) in
  100. make.edges.equalTo(view.safeAreaLayoutGuide.snp.edges)
  101. }
  102. if UITraitCollection.current.userInterfaceStyle == .dark {
  103. view.backgroundColor = .black
  104. generateView.layer.borderColor = UIColor.white.cgColor
  105. promptTextField.layer.borderColor = UIColor.white.cgColor
  106. negativePromptTextField.layer.borderColor = UIColor.white.cgColor
  107. generateImage.layer.borderColor = UIColor.white.cgColor
  108. remindText.textColor = .white
  109. } else {
  110. view.backgroundColor = .white
  111. generateView.layer.borderColor = UIColor.black.cgColor
  112. promptTextField.layer.borderColor = UIColor.black.cgColor
  113. negativePromptTextField.layer.borderColor = UIColor.black.cgColor
  114. generateImage.layer.borderColor = UIColor.black.cgColor
  115. remindText.textColor = .systemGray5
  116. }
  117. self.title = "画酱"
  118. delegate = UIApplication.shared.delegate as? AppDelegate
  119. drawModeView.addSubview(generateView)
  120. generateView.addSubview(promptTextField)
  121. generateView.addSubview(negativePromptTextField)
  122. generateView.addSubview(generateButton)
  123. longPress = UILongPressGestureRecognizer(target: self, action: #selector(saveImageToPhotos))
  124. generateImage.addGestureRecognizer(longPress!)
  125. generateView.snp.makeConstraints { (make) in
  126. make.top.equalTo(drawModeView.contentLayoutGuide.snp.top)
  127. make.centerX.equalTo(view.safeAreaLayoutGuide.snp.centerX)
  128. make.left.equalTo(drawModeView.contentLayoutGuide.snp.left).offset(5)
  129. make.right.equalTo(drawModeView.contentLayoutGuide.snp.right).offset(-5)
  130. make.height.equalTo(drawModeView.contentLayoutGuide.snp.width).multipliedBy(0.75)
  131. }
  132. promptTextField.snp.makeConstraints { (make) in
  133. make.top.equalTo(generateView.snp.top).offset(5)
  134. make.left.equalTo(generateView.snp.left).offset(5)
  135. make.right.equalTo(generateView.snp.right).offset(-5)
  136. make.height.equalTo(generateView.snp.height).multipliedBy(0.4)
  137. make.centerX.equalTo(generateView.snp.centerX)
  138. }
  139. promptTextField.delegate = self
  140. negativePromptTextField.snp.makeConstraints { (make) in
  141. make.top.equalTo(promptTextField.snp.bottom).offset(5)
  142. make.left.equalTo(generateView.snp.left).offset(5)
  143. make.right.equalTo(generateView.snp.right).offset(-5)
  144. make.height.equalTo(generateView.snp.height).multipliedBy(0.32)
  145. make.centerX.equalTo(generateView.snp.centerX)
  146. }
  147. negativePromptTextField.delegate = self
  148. generateButton.snp.makeConstraints { (make) in
  149. make.top.equalTo(negativePromptTextField.snp.bottom).offset(5)
  150. make.width.equalTo(generateView.snp.width).multipliedBy(0.97)
  151. make.bottom.equalTo(generateView.snp.bottom).offset(-5)
  152. make.centerX.equalTo(generateView.snp.centerX)
  153. }
  154. drawModeView.addSubview(imageUploadView)
  155. imageUploadView.addSubview(pic2PicLabel)
  156. imageUploadView.addSubview(uploadImage)
  157. imageUploadView.snp.makeConstraints { (make) in
  158. make.top.equalTo(generateView.snp.bottom).offset(5)
  159. make.left.equalTo(drawModeView.contentLayoutGuide.snp.left).offset(5)
  160. make.right.equalTo(drawModeView.contentLayoutGuide.snp.right).offset(-5)
  161. make.centerX.equalTo(drawModeView.contentLayoutGuide.snp.centerX)
  162. make.height.equalTo(imageUploadView.snp.width).multipliedBy(0.4)
  163. }
  164. pic2PicLabel.snp.makeConstraints { (make) in
  165. make.left.equalTo(imageUploadView.snp.left).offset(5)
  166. make.top.equalTo(imageUploadView.snp.top).offset(5)
  167. make.width.equalTo(imageUploadView.snp.width)
  168. make.height.equalTo(25)
  169. }
  170. uploadImage.snp.makeConstraints { (make) in
  171. make.top.equalTo(pic2PicLabel.snp.bottom).offset(5)
  172. make.bottom.equalTo(imageUploadView.snp.bottom)
  173. make.left.equalTo(imageUploadView.snp.left).offset(5)
  174. make.right.equalTo(imageUploadView.snp.right).offset(-5)
  175. }
  176. drawModeView.addSubview(remindText)
  177. drawModeView.addSubview(generateImage)
  178. generateImage.snp.makeConstraints { (make) in
  179. make.top.equalTo(imageUploadView.snp.bottom).offset(10)
  180. make.left.equalTo(drawModeView.contentLayoutGuide.snp.left).offset(5)
  181. make.right.equalTo(drawModeView.contentLayoutGuide.snp.right).offset(-5)
  182. make.centerX.equalTo(drawModeView.contentLayoutGuide.snp.centerX)
  183. make.height.equalTo(generateImage.snp.width)
  184. make.bottom.equalTo(drawModeView.contentLayoutGuide.snp.bottom)
  185. }
  186. remindText.snp.makeConstraints { (make) in
  187. make.top.equalTo(generateImage.snp.top).offset(2)
  188. make.width.equalTo(generateImage.snp.width)
  189. make.height.equalTo(generateImage.snp.height).multipliedBy(0.40)
  190. make.centerX.equalTo(generateImage.snp.centerX)
  191. }
  192. }
  193. override func viewWillAppear(_ animated: Bool) {
  194. if !userDefaults.bool(forKey: UserDefaultKeys.UserInfo.isLogin) {
  195. generateButton.setTitle("请登录后使用", for: .normal)
  196. generateButton.isEnabled = false
  197. } else {
  198. generateButton.setTitle("生成图片", for: .normal)
  199. generateButton.isEnabled = true
  200. }
  201. }
  202. func translatePrompt(prompt: String, negativePrompt: String, completion: @escaping (_ tranPrompt: String, _ tranNegativePrompt: String) -> Void) {
  203. let APP_KEY = "3bb96f14d2af67ec"
  204. let APP_SECRET = "SRQF1jGwAMuYciFK33KfyRGKa7B1x38u"
  205. let q = prompt + "@" + negativePrompt
  206. let salt = UUID().uuidString
  207. let curtime = Int(Date().timeIntervalSince1970)
  208. let inputQ = q.count <= 20 ? q : String(q.prefix(10)) + String(q.count) + String(q.suffix(10))
  209. let signStr = APP_KEY + inputQ + salt + String(curtime) + APP_SECRET
  210. let cryptoSign = signStr.sha256
  211. let paramDic = ["q": q, "from": "auto", "to": "en", "appKey": APP_KEY, "salt": salt, "sign": cryptoSign, "signType": "v3", "curtime": String(curtime)]
  212. let list = NSMutableArray()
  213. for subDic in paramDic {
  214. let tmpStr = "\(subDic.0)=\(subDic.1)"
  215. list.add(tmpStr)
  216. }
  217. let paramStr = list.componentsJoined(by: "&")
  218. let paramData = APIs.YouDao.TextTranslate + "api?" + paramStr
  219. print(paramData)
  220. guard let addr = paramData.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {
  221. print("error")
  222. return
  223. }
  224. guard let url = URL(string: addr) else {
  225. print("error")
  226. return
  227. }
  228. var request = URLRequest(url: url)
  229. request.httpMethod = "GET"
  230. var promptValue = ""
  231. var negativePromotValue = ""
  232. let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
  233. do {
  234. guard let unwrapedData = data else {
  235. print("error")
  236. return
  237. }
  238. let jsonData = try JSON(data: unwrapedData)
  239. let promptData = jsonData["translation"][0].stringValue
  240. print(promptData)
  241. if String(promptData) == "@" {
  242. } else {
  243. if String(promptData.first ?? String.Element("")) == "@" {
  244. if #available(iOS 16.0, *) {
  245. let subStringArr = promptData.split(separator: "@")
  246. negativePromotValue = String(subStringArr[0])
  247. } else {
  248. // Fallback on earlier versions
  249. let subStringArr = promptData.components(separatedBy: "@")
  250. negativePromotValue = String(subStringArr[0])
  251. }
  252. } else if String(promptData.last ?? String.Element("")) == "@" {
  253. if #available(iOS 16.0, *) {
  254. let subStringArr = promptData.split(separator: " @")
  255. promptValue = String(subStringArr[0])
  256. } else {
  257. // Fallback on earlier versions
  258. let subStringArr = promptData.components(separatedBy: "@")
  259. promptValue = String(subStringArr[0])
  260. }
  261. } else if promptData == "@"{
  262. // do nothing
  263. } else {
  264. if #available(iOS 16.0, *) {
  265. let subStringArr = promptData.split(separator: "@")
  266. promptValue = String(subStringArr[0])
  267. negativePromotValue = String(subStringArr[1])
  268. } else {
  269. // Fallback on earlier versions
  270. let subStringArr = promptData.components(separatedBy: "@")
  271. promptValue = String(subStringArr[0])
  272. negativePromotValue = String(subStringArr[1])
  273. }
  274. }
  275. }
  276. } catch {}
  277. completion(promptValue, negativePromotValue)
  278. }
  279. task.resume()
  280. }
  281. @objc func generateAction() {
  282. let promptText = promptTextField.text ?? ""
  283. let negativePromptText = negativePromptTextField.text ?? ""
  284. translatePrompt(prompt: promptTextField.text!, negativePrompt: negativePromptTextField.text!) { [self] promptValue, negativePromotValue in
  285. prompt = "masterpiece, best quality, " + promptValue
  286. negativePrompt = "lowres, bad anatomy, bad hands, text, error, missing fingers, extra digits, fewer digits, cropped, worst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry, bad feet, " + negativePromotValue
  287. sessionHash = UUID().uuidString.replacingOccurrences(of: "-", with: "").lowercased()
  288. guard let unwrapedDelegate = delegate else {
  289. return
  290. }
  291. context = unwrapedDelegate.persistentContainer.viewContext
  292. painting = NSEntityDescription.insertNewObject(forEntityName: "Painting", into: context!) as? Painting
  293. painting?.prompt = promptText
  294. painting?.negative_prompt = negativePromptText
  295. painting?.session_hash = sessionHash
  296. painting?.create_time = Date()
  297. guard let userID = userDefaults.string(forKey: UserDefaultKeys.UserInfo.userId) else {
  298. return
  299. }
  300. if pickedImage != nil {
  301. let imgBase64 = pickedImage?.pngData()?.base64EncodedString()
  302. let imgStr = "data:image/png;base64," + imgBase64!
  303. let postData: [String: String] = ["userId": userID, "img": imgStr, "prompt": prompt, "negPrompt": negativePrompt, "sessionHash": sessionHash]
  304. AF.request(APIs.Draw.Pic2Pic, method: .post, parameters: postData, encoder: URLEncodedFormParameterEncoder.default).response { [self] response in
  305. switch response.result {
  306. case .success(let data):
  307. guard let json = try? JSON(data: data!) else {
  308. return
  309. }
  310. let imageAddr = json["result"].stringValue
  311. let addrProcess = imageAddr.replacingOccurrences(of: "\\", with: "/")
  312. let url = URL(string: addrProcess)
  313. generateImage.downloadedFrom(link: addrProcess)
  314. let dataTask = URLSession.shared.dataTask(with: url!) { [self] (data, response, error) in
  315. painting?.image = data
  316. saveContext()
  317. }
  318. dataTask.resume()
  319. DispatchQueue.main.async { [self] in
  320. self.generateButton.backgroundColor = .blue
  321. self.generateButton.isUserInteractionEnabled = true
  322. }
  323. break
  324. case .failure(let error):
  325. print(error)
  326. break
  327. }
  328. }
  329. } else {
  330. let postData: [String: String] = ["userId": userID, "prompt": prompt, "negPrompt": negativePrompt, "sessionHash": sessionHash]
  331. AF.request(APIs.Draw.Text2Pic, method: .post, parameters: postData, encoder: URLEncodedFormParameterEncoder.default).response { [self] response in
  332. switch response.result {
  333. case .success(let data):
  334. guard let json = try? JSON(data: data!) else {
  335. return
  336. }
  337. let imageAddr = json["result"].stringValue
  338. let addrProcess = imageAddr.replacingOccurrences(of: "\\", with: "/")
  339. let url = URL(string: addrProcess)
  340. generateImage.downloadedFrom(link: addrProcess)
  341. let dataTask = URLSession.shared.dataTask(with: url!) { [self] (data, response, error) in
  342. painting?.image = data
  343. saveContext()
  344. }
  345. dataTask.resume()
  346. DispatchQueue.main.async { [self] in
  347. self.generateButton.backgroundColor = .blue
  348. self.generateButton.isUserInteractionEnabled = true
  349. }
  350. break
  351. case .failure(let error):
  352. print(error)
  353. break
  354. }
  355. }
  356. }
  357. }
  358. generateButton.backgroundColor = .gray
  359. generateButton.isUserInteractionEnabled = false
  360. }
  361. var allowEditing = true
  362. @objc func pickPhotoFromAlbum() {
  363. if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) {
  364. let picker = UIImagePickerController()
  365. picker.delegate = self
  366. picker.sourceType = .photoLibrary
  367. picker.allowsEditing = allowEditing
  368. self.present(picker, animated: true)
  369. } else {
  370. print("读取相册时出错!")
  371. }
  372. }
  373. func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
  374. let image: UIImage!
  375. if allowEditing {
  376. image = info[.editedImage] as? UIImage
  377. } else {
  378. image = info[.originalImage] as? UIImage
  379. }
  380. uploadImage.image = image
  381. pickedImage = image
  382. picker.dismiss(animated: true)
  383. }
  384. @objc func saveImageToPhotos() {
  385. if (longPress!.state == .began) {
  386. guard let img = generateImage.image else {
  387. print("error")
  388. return
  389. }
  390. switch PHPhotoLibrary.authorizationStatus() {
  391. case .authorized:
  392. saveImg(image: img)
  393. case .notDetermined:
  394. PHPhotoLibrary.requestAuthorization { (status) in
  395. if status == .authorized {
  396. self.saveImg(image: img)
  397. } else {
  398. print("用户拒绝访问")
  399. }
  400. }
  401. case .restricted, .denied:
  402. if let url = URL.init(string: UIApplication.openSettingsURLString) {
  403. if UIApplication.shared.canOpenURL(url) {
  404. UIApplication.shared.open(url)
  405. }
  406. }
  407. case .limited:
  408. return
  409. @unknown default:
  410. return
  411. }
  412. }else if (longPress!.state == .ended){
  413. return
  414. }
  415. }
  416. func saveContext() {
  417. if context!.hasChanges {
  418. do {
  419. try context?.save()
  420. print("save success.")
  421. } catch {}
  422. }
  423. }
  424. func saveImg(image: UIImage) {
  425. PHPhotoLibrary.shared().performChanges({
  426. PHAssetChangeRequest.creationRequestForAsset(from: image)
  427. }, completionHandler: { (isSuccess, error) in
  428. DispatchQueue.main.async {
  429. if isSuccess{
  430. self.present(self.alertController, animated: true, completion: nil)
  431. DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2) {
  432. self.alertController.dismiss(animated: false)
  433. }
  434. }
  435. }
  436. })
  437. }
  438. override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
  439. promptTextField.resignFirstResponder()
  440. negativePromptTextField.resignFirstResponder()
  441. }
  442. override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
  443. if #available(iOS 13, *) {
  444. if self.traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) {
  445. if self.traitCollection.userInterfaceStyle == .dark {
  446. // 黑夜模式
  447. view.backgroundColor = .black
  448. generateView.layer.borderColor = UIColor.white.cgColor
  449. promptTextField.layer.borderColor = UIColor.white.cgColor
  450. negativePromptTextField.layer.borderColor = UIColor.white.cgColor
  451. generateImage.layer.borderColor = UIColor.white.cgColor
  452. remindText.textColor = .white
  453. } else {
  454. // 白天模式
  455. view.backgroundColor = .white
  456. generateView.layer.borderColor = UIColor.black.cgColor
  457. promptTextField.layer.borderColor = UIColor.black.cgColor
  458. negativePromptTextField.layer.borderColor = UIColor.black.cgColor
  459. generateImage.layer.borderColor = UIColor.black.cgColor
  460. remindText.textColor = .systemGray5
  461. }
  462. }
  463. }
  464. }
  465. }
  466. extension DrawViewController: UITextFieldDelegate {
  467. func textFieldShouldReturn(_ textField: UITextField) -> Bool {
  468. self.view?.endEditing(false)
  469. return true
  470. }
  471. }