前提・実現したいこと
動画にテキストを合成してカメラロールに保存するときにCATextLayerの行間を狭めて保存したい
Swift
import UIKit import AVFoundation import AVKit import Photos class ViewController: UIViewController { var myurl: URL? override func viewDidLoad() { super.viewDidLoad() } @IBAction func saveVideoTapper(_ sender: Any) { let path = Bundle.main.path(forResource: "sample_video", ofType:"mp4") let fileURL = NSURL(fileURLWithPath: path!) let composition = AVMutableComposition() let vidAsset = AVURLAsset(url: fileURL as URL, options: nil) // get video track let vtrack = vidAsset.tracks(withMediaType: AVMediaType.video) let videoTrack: AVAssetTrack = vtrack[0] let vid_timerange = CMTimeRangeMake(start: CMTime.zero, duration: vidAsset.duration) let tr: CMTimeRange = CMTimeRange(start: CMTime.zero, duration: CMTime(seconds: 10.0, preferredTimescale: 600)) composition.insertEmptyTimeRange(tr) let trackID:CMPersistentTrackID = CMPersistentTrackID(kCMPersistentTrackID_Invalid) if let compositionvideoTrack: AVMutableCompositionTrack = composition.addMutableTrack(withMediaType: AVMediaType.video, preferredTrackID: trackID) { do { try compositionvideoTrack.insertTimeRange(vid_timerange, of: videoTrack, at: CMTime.zero) } catch { print("error") } compositionvideoTrack.preferredTransform = videoTrack.preferredTransform } else { print("unable to add video track") return } // Watermark Effect let size = videoTrack.naturalSize let imglogo = UIImage(named: "image.png") let imglayer = CALayer() imglayer.contents = imglogo?.cgImage imglayer.frame = CGRect(x: 5, y: 5, width: 100, height: 100) imglayer.opacity = 0.6 // create text Layer let titleLayer = CATextLayer() titleLayer.backgroundColor = UIColor.white.cgColor titleLayer.isWrapped = true titleLayer.truncationMode = .end titleLayer.alignmentMode = CATextLayerAlignmentMode.center titleLayer.frame = CGRect(x: 0, y: 50, width: size.width, height: size.height / 6) var attributes: [NSAttributedString.Key: Any] = [.foregroundColor: UIColor.white, .font: UIFont.systemFont(ofSize: 26, weight: .bold)] let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineSpacing = 0 paragraphStyle.alignment = .center attributes.updateValue(paragraphStyle, forKey: .paragraphStyle) let attributeString = NSAttributedString(string:"DuummyText\nDummuyText", attributes: attributes) textLayer.string = attributeString let videolayer = CALayer() videolayer.frame = CGRect(x: 0, y: 0, width: size.width, height: size.height) let parentlayer = CALayer() parentlayer.frame = CGRect(x: 0, y: 0, width: size.width, height: size.height) parentlayer.addSublayer(videolayer) parentlayer.addSublayer(imglayer) parentlayer.addSublayer(titleLayer) let layercomposition = AVMutableVideoComposition() layercomposition.frameDuration = CMTimeMake(value: 1, timescale: 30) layercomposition.renderSize = size layercomposition.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: videolayer, in: parentlayer) // instruction for watermark let instruction = AVMutableVideoCompositionInstruction() instruction.timeRange = CMTimeRangeMake(start: CMTime.zero, duration: composition.duration) let videotrack = composition.tracks(withMediaType: AVMediaType.video)[0] as AVAssetTrack let layerinstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: videotrack) instruction.layerInstructions = NSArray(object: layerinstruction) as [AnyObject] as! [AVVideoCompositionLayerInstruction] layercomposition.instructions = NSArray(object: instruction) as [AnyObject] as! [AVVideoCompositionInstructionProtocol] // create new file to receive data let dirPaths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true) let docsDir = dirPaths[0] as NSString let movieFilePath = docsDir.appendingPathComponent("result.mov") let movieDestinationUrl = NSURL(fileURLWithPath: movieFilePath) // use AVAssetExportSession to export video let assetExport = AVAssetExportSession(asset: composition, presetName:AVAssetExportPresetHighestQuality) assetExport?.outputFileType = AVFileType.mov assetExport?.videoComposition = layercomposition // Check exist and remove old file FileManager.default.removeItemIfExisted(movieDestinationUrl as URL) assetExport?.outputURL = movieDestinationUrl as URL assetExport?.exportAsynchronously(completionHandler: { switch assetExport!.status { case AVAssetExportSession.Status.failed: print("failed") print(assetExport?.error ?? "unknown error") case AVAssetExportSession.Status.cancelled: print("cancelled") print(assetExport?.error ?? "unknown error") default: print("Movie complete") self.myurl = movieDestinationUrl as URL PHPhotoLibrary.shared().performChanges({ PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: movieDestinationUrl as URL) }) { saved, error in if saved { print("Saved") } } self.playVideo() } }) } func playVideo() { let player = AVPlayer(url: myurl!) let playerLayer = AVPlayerLayer(player: player) playerLayer.frame = self.view.bounds self.view.layer.addSublayer(playerLayer) player.play() print("playing...") } } extension FileManager { func removeItemIfExisted(_ url:URL) -> Void { if FileManager.default.fileExists(atPath: url.path) { do { try FileManager.default.removeItem(atPath: url.path) } catch { print("Failed to delete file") } } } }
試したこと
NSMutableParagraphStyleのlineSpacing,paragraphSpacingを使って試したが変わらなかった
CATextLayer の string には NSAttributedString が設定できるので、こんな感じでいけるのでは。
(titleLabel.attributedText = 〜 の代わりに titleLayer.string = NSAttributedString(〜) とする。)
https://qiita.com/k0uhashi/items/bb8de77626fa1e73b080#%E3%82%B3%E3%83%BC%E3%83%89%E3%81%8B%E3%82%89%E5%8B%95%E7%9A%84%E3%81%AB%E5%A4%89%E6%9B%B4%E3%81%99%E3%82%8B
NSAttributedStringを使って見たのですが、NSMutableParagraphStyleの部分が適用されませんでした。
NSAttributeStringnに変更したコードを追加しました。
lineSpacing じゃなくて paragraphSpacing かも。あと、行間を狭めるにはマイナスにするといいはず。
https://stackoverflow.com/a/12562660
返信ありがとうございます。
paragraphSpacingを設定したのですが、こちらも効果なしでした。
回答1件
あなたの回答
tips
プレビュー