前提・実現したいこと
URLからAVAssetに変換し、その上からロゴと文字を合成し書き出す処理をしています。
その時にCATextLayerを使い文字を書き合成しているのですが、TextViewを使うことはできないでしょうか?
Tiktokのこちらの動画のように文字を縁取る文字を合成したいため以下リンクのTextViewを使いたいと思ってます。
TextViewの参考にした記事
該当のソースコード
swift
1import UIKit 2import AVFoundation 3import AVKit 4import Photos 5 6class ViewController: UIViewController { 7 8var myurl: URL? 9 10override func viewDidLoad() { 11 super.viewDidLoad() 12} 13 14@IBAction func saveVideoTapper(_ sender: Any) { 15 16 let path = Bundle.main.path(forResource: "sample_video", ofType:"mp4") 17 let fileURL = NSURL(fileURLWithPath: path!) 18 19 let composition = AVMutableComposition() 20 let vidAsset = AVURLAsset(url: fileURL as URL, options: nil) 21 22 // get video track 23 let vtrack = vidAsset.tracks(withMediaType: AVMediaType.video) 24 let videoTrack: AVAssetTrack = vtrack[0] 25 let vid_timerange = CMTimeRangeMake(start: CMTime.zero, duration: vidAsset.duration) 26 27 let tr: CMTimeRange = CMTimeRange(start: CMTime.zero, duration: CMTime(seconds: 10.0, preferredTimescale: 600)) 28 composition.insertEmptyTimeRange(tr) 29 30 let trackID:CMPersistentTrackID = CMPersistentTrackID(kCMPersistentTrackID_Invalid) 31 32 if let compositionvideoTrack: AVMutableCompositionTrack = composition.addMutableTrack(withMediaType: AVMediaType.video, preferredTrackID: trackID) { 33 34 do { 35 try compositionvideoTrack.insertTimeRange(vid_timerange, of: videoTrack, at: CMTime.zero) 36 } catch { 37 print("error") 38 } 39 40 compositionvideoTrack.preferredTransform = videoTrack.preferredTransform 41 42 } else { 43 print("unable to add video track") 44 return 45 } 46 47 48 // Watermark Effect 49 let size = videoTrack.naturalSize 50 51 let imglogo = UIImage(named: "image.png") 52 let imglayer = CALayer() 53 imglayer.contents = imglogo?.cgImage 54 imglayer.frame = CGRect(x: 5, y: 5, width: 100, height: 100) 55 imglayer.opacity = 0.6 56 57 // create text Layer 58 let titleLayer = CATextLayer() 59 titleLayer.backgroundColor = UIColor.white.cgColor 60 titleLayer.isWrapped = true 61 titleLayer.truncationMode = .end 62 titleLayer.alignmentMode = CATextLayerAlignmentMode.center 63 titleLayer.frame = CGRect(x: 0, y: 50, width: size.width, height: size.height / 6) 64 var attributes: [NSAttributedString.Key: Any] = [.foregroundColor: UIColor.white, .font: UIFont.systemFont(ofSize: 26, weight: .bold)] 65 let paragraphStyle = NSMutableParagraphStyle() 66 paragraphStyle.lineSpacing = 0 67 paragraphStyle.alignment = .center 68 attributes.updateValue(paragraphStyle, forKey: .paragraphStyle) 69 let attributeString = NSAttributedString(string:"DuummyText\nDummuyText", attributes: attributes) 70 textLayer.string = attributeString 71 72 73 let videolayer = CALayer() 74 videolayer.frame = CGRect(x: 0, y: 0, width: size.width, height: size.height) 75 76 let parentlayer = CALayer() 77 parentlayer.frame = CGRect(x: 0, y: 0, width: size.width, height: size.height) 78 parentlayer.addSublayer(videolayer) 79 parentlayer.addSublayer(imglayer) 80 parentlayer.addSublayer(titleLayer) 81 82 let layercomposition = AVMutableVideoComposition() 83 layercomposition.frameDuration = CMTimeMake(value: 1, timescale: 30) 84 layercomposition.renderSize = size 85 layercomposition.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: videolayer, in: parentlayer) 86 87 // instruction for watermark 88 let instruction = AVMutableVideoCompositionInstruction() 89 instruction.timeRange = CMTimeRangeMake(start: CMTime.zero, duration: composition.duration) 90 let videotrack = composition.tracks(withMediaType: AVMediaType.video)[0] as AVAssetTrack 91 let layerinstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: videotrack) 92 instruction.layerInstructions = NSArray(object: layerinstruction) as [AnyObject] as! [AVVideoCompositionLayerInstruction] 93 layercomposition.instructions = NSArray(object: instruction) as [AnyObject] as! [AVVideoCompositionInstructionProtocol] 94 95 // create new file to receive data 96 let dirPaths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true) 97 let docsDir = dirPaths[0] as NSString 98 let movieFilePath = docsDir.appendingPathComponent("result.mov") 99 let movieDestinationUrl = NSURL(fileURLWithPath: movieFilePath) 100 101 // use AVAssetExportSession to export video 102 let assetExport = AVAssetExportSession(asset: composition, presetName:AVAssetExportPresetHighestQuality) 103 assetExport?.outputFileType = AVFileType.mov 104 assetExport?.videoComposition = layercomposition 105 106 // Check exist and remove old file 107 FileManager.default.removeItemIfExisted(movieDestinationUrl as URL) 108 109 assetExport?.outputURL = movieDestinationUrl as URL 110 assetExport?.exportAsynchronously(completionHandler: { 111 switch assetExport!.status { 112 case AVAssetExportSession.Status.failed: 113 print("failed") 114 print(assetExport?.error ?? "unknown error") 115 case AVAssetExportSession.Status.cancelled: 116 print("cancelled") 117 print(assetExport?.error ?? "unknown error") 118 default: 119 print("Movie complete") 120 121 self.myurl = movieDestinationUrl as URL 122 123 PHPhotoLibrary.shared().performChanges({ 124 PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: movieDestinationUrl as URL) 125 }) { saved, error in 126 if saved { 127 print("Saved") 128 } 129 } 130 131 self.playVideo() 132 133 } 134 }) 135 136} 137 138 139func playVideo() { 140 let player = AVPlayer(url: myurl!) 141 let playerLayer = AVPlayerLayer(player: player) 142 playerLayer.frame = self.view.bounds 143 self.view.layer.addSublayer(playerLayer) 144 player.play() 145 print("playing...") 146} 147 148 149 150} 151 152 153extension FileManager { 154func removeItemIfExisted(_ url:URL) -> Void { 155 if FileManager.default.fileExists(atPath: url.path) { 156 do { 157 try FileManager.default.removeItem(atPath: url.path) 158 } 159 catch { 160 print("Failed to delete file") 161 } 162 } 163} 164}
CATextLayerに関してDocumentationに何と書いてありますか?以下のようにあります。
A layer that provides simple text layout and rendering of plain or attributed strings.
CATextLayerのstringのタイプは文字列ではありません。NSAtttributedのobjectも渡すことができるようなので、試してみてはどうでしょう?
コメントありがとうございます。
NSAttributeだけではこの文字の背景を縁取る文字列の作り方がわからないです。
それができればNSAttributeStringをUIGraphicsBeginImageContext使って画像化できそうです。
あなたの回答
tips
プレビュー