質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

0回答

771閲覧

動画にTextViewを合成して書き出したい

Yeezy21

総合スコア21

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2021/04/05 10:37

前提・実現したいこと

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}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tomato879241

2021/04/05 10:59

CATextLayerに関してDocumentationに何と書いてありますか?以下のようにあります。 A layer that provides simple text layout and rendering of plain or attributed strings. CATextLayerのstringのタイプは文字列ではありません。NSAtttributedのobjectも渡すことができるようなので、試してみてはどうでしょう?
Yeezy21

2021/04/05 11:26

コメントありがとうございます。 NSAttributeだけではこの文字の背景を縁取る文字列の作り方がわからないです。 それができればNSAttributeStringをUIGraphicsBeginImageContext使って画像化できそうです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問