How do you save a picture from the capture-screen with AVCaptureSession to Photo? My capture-screen looks like a square as show below.
Yet I've ended up with an 1080 × 1920 image as shown below. I have an iPhone XR, and I always end up with 1080 × 1920 images. How come the aspect ration never changes?
My code has the following lines
import UIKit
import AVFoundation
class CaptureViewController: UIViewController, AVCapturePhotoCaptureDelegate {
var captureSession: AVCaptureSession!
var cameraDevices: AVCaptureDevice!
var imagePhotoOutput: AVCapturePhotoOutput!
enum CameraCase {
case front
case back
}
// MARK: - IBAction
@IBAction func takePictureTapped(_ sender: UIButton) {
snapPicture()
}
// MARK: - Life cycle
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
prepareCamera(cameraCase: .back)
}
// MARK: - Camera
func prepareCamera(cameraCase: CameraCase) {
/* removing existing layers */
if let sublayers = self.view.layer.sublayers {
for sublayer in sublayers {
if sublayer.isKind(of: AVCaptureVideoPreviewLayer.self) {
sublayer.removeFromSuperlayer()
}
}
}
/* creating a capture session */
captureSession = AVCaptureSession()
guard let device = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaType.video, position: cameraCase == .front ? .front : .back).devices.first else { return }
let videoInput = try? AVCaptureDeviceInput(device: device)
if captureSession.canAddInput(videoInput!) {
captureSession.addInput(videoInput!)
imagePhotoOutput = AVCapturePhotoOutput() // setting output destination
captureSession.addOutput(imagePhotoOutput) // adding photo output to session
}
/* creating a capture layer */
let previewLayer: AVCaptureVideoPreviewLayer = AVCaptureVideoPreviewLayer.init(session: captureSession)
previewLayer.frame = CGRect(x: 0.0, y: 200.0, width: view.frame.width, height: view.frame.height - 500.0)
previewLayer.videoGravity = AVLayerVideoGravity.resize
/* adding video capture layer to the view layer */
self.view.layer.addSublayer(previewLayer)
/* starting capture session */
DispatchQueue.global(qos: .background).async {
self.captureSession.startRunning()
}
}
func snapPicture() {
let settingsForMonitoring = AVCapturePhotoSettings()
imagePhotoOutput?.capturePhoto(with: settingsForMonitoring, delegate: self as AVCapturePhotoCaptureDelegate)
}
// MARK: - Delegate methods
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
if error == nil {
guard let imageData = photo.fileDataRepresentation() else {
print("Error while generating image from photo capture data.");
return
}
if let image = UIImage(data: imageData) {
saveImage(image)
}
}
}
// MARK: - Saving an image to Photo Library
func saveImage(_ image: UIImage) {
UIImageWriteToSavedPhotosAlbum(image, self, #selector(image(_:didFinishSavingWithError: contextInfo:)), nil)
}
@objc func image(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) {
if let error = error {
print("An error has occurred: \(error.localizedDescription)")
} else {
print("Saved...")
}
}
}
Thanks.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I'm using the custom URL scheme to open my app through Safari. When the app appears, the status bar shows 'Safari' at the top-left corner. Is there a way of stopping the app from showing Safari's name? I don't want the user to tap the name and go back to Safari. There is nothing special in my SceneDelegate. So I wonder if it's probably the matter of settings in the Settings app? Thanks.
I have a simple app that implements a custom URL scheme. When I enter the scheme for my app in Safari, the app will launch itself. So far, so good... Now, when I initiate the app switcher, I have my app and the web browser (Safari). Is there a way of not showing them in the app switcher? Or can I at least stop the web browser from appearing in the app switcher? Is it even possible for me to terminate Safari programmatically from my app, provided that that is not going to violate the app store guidelines? Thanks.
Drawing a pie isn't difficult if I do it with Path.
import SwiftUI
struct ContentView8: View {
var body: some View {
PieSlice(start: .degrees(-90), end: .degrees(120))
.fill(.pink)
}
}
struct PieSlice: Shape {
let start: Angle
let end: Angle
func path(in rect: CGRect) -> Path {
var path = Path()
let center = CGPoint(x: rect.midX, y: rect.midY)
path.move(to: center)
path.addArc(center: center, radius: rect.midX, startAngle: start, endAngle: end, clockwise: false)
return path
}
}
Actually, I want to animate this pie such that it will gradually deploy starting at -90 degrees. In the code above, I suppose I cannot animate the pie because the PieSlice guy isn't a View. Or can I? If I can't, is there an alternative way of drawing a pie so that I can animate it?
Thanks a million.
Señor Tomato Source
Hostage Negotiator at
Tomato Source Association of North America
I use the ForEach enumeration to list a View horizontally. And I get the following picture.
So far, so good... If I select the 5th object or 6th one, something odd (< More) appears. I don't know where it comes from. I have never seen it before. How does it happen? I wonder how I can remove it? I have searched the net for a clue to no avail. I don't even know how to describe it.
The following is my code.
import SwiftUI
struct ContentView: View {
@State var selectedTab = 0
@State var addTapped = false
@State var refresh = false
@State var people = [
Person(name: "Alice", systemImage: "person.circle.fill"),
Person(name: "Jane", systemImage: "person.circle.fill"),
Person(name: "Dave", systemImage: "person.circle.fill"),
Person(name: "Susan", systemImage: "person.circle.fill"),
Person(name: "Robert", systemImage: "person.circle.fill"),
Person(name: "Daniel", systemImage: "person.circle.fill")
]
var body: some View {
VStack(alignment: .leading, spacing: 0) {
ScrollView(.horizontal) {
HStack(spacing: 20) {
ForEach(0..<people.count, id: \.self) { num in
VStack {
let person = people[num]
Image(systemName: person.systemImage)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(height: 32)
Text(person.name)
.fixedSize()
}
.foregroundColor(selectedTab == num ? Color.blue : Color.gray)
.onTapGesture {
self.selectedTab = num
}
}
}
}.padding(.horizontal, 10)
Spacer()
.frame(height: 2)
Rectangle().fill(.gray)
.frame(height: 1)
TabView(selection: $selectedTab) {
ForEach(0..<people.count, id: \.self) { num in
let person = people[num]
Text(person.name)
.tag(person.id)
}
}
}
}
}
struct Person: Identifiable {
let id = UUID()
let name: String
let systemImage: String
}
Muchos thankos.
I'm trying to export a document file. It contains a codable struct named NoteGroup.
struct NoteGroup: Codable {
let id: UUID
let name: String
let createAt: Date
let children: [NoteChild]
init(id: UUID = .init(), name: String = "", createAt: Date = .init(), children: [NoteChild]) {
self.id = id
self.name = name
self.createAt = createAt
self.children = children
}
}
, which contains another object named NoteChild. I have a FileDocument struct as follows.
import SwiftUI
import UniformTypeIdentifiers
struct Document: FileDocument {
var document: NoteGroup
static var readableContentTypes = [UTType.frogType]
init(document: NoteGroup = NoteGroup(children: [NoteChild(id: UUID(), name: "", createAt: Date())])) {
self.document = document
}
init(configuration: ReadConfiguration) throws {
self.init()
}
func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
do {
let data = try getDocumentData()
let jsonFileWrapper = FileWrapper(regularFileWithContents: data)
let filename = "Note.frog"
jsonFileWrapper.filename = filename
let fileWrapper = FileWrapper(directoryWithFileWrappers: [filename: jsonFileWrapper])
return fileWrapper
} catch {
throw error
}
}
private func getDocumentData() throws -> Data {
let encoder = JSONEncoder()
do {
let data = try encoder.encode(document)
return data
} catch {
throw error
}
}
}
extension UTType {
public static let frogType = UTType(exportedAs: "com.example.frog")
}
And I export a file like the following.
import SwiftUI
import UniformTypeIdentifiers
struct ContentView: View {
@State private var showingExporter = false
@State var doc = Document()
var body: some View {
VStack {
Button("Tap to export") {
showingExporter.toggle()
}
.fileExporter(
isPresented: $showingExporter,
document: doc,
contentType: .frogType
) { result in
switch result {
case .success(let file):
print(file)
case .failure(let error):
print(error)
}
}
}.onAppear {
doc = Document(document: NoteGroup(id: UUID(), name: "Kyle", createAt: Date(), children: [NoteChild(id: UUID(), name: "Nancy", createAt: Date())]))
}
}
}
Well, I have read this topic. And I've watched this video about Uniform Type Identifiers. Thanks to the video, I am able to export a file. Yet, I end up with a folder (Frog.frog), not a packaged file. There is a JSON file in it, though. What am I doing wrong? It's for iOS. La vida no es facil. Muchos thankos.
I have created a simple case to make my point as follows.
import SwiftUI
struct ContentView: View {
var body: some View {
ZStack {
Color.yellow.ignoresSafeArea()
VStack(alignment: .leading) {
ForEach(Fruit.allCases, id: \.self) { fruit in
DisclosureGroup(fruit.rawValue) {
VStack {
Text("1")
Text("2")
Text("3")
}
}
.contextMenu {
Button("Hello", action: {
})
}
}
}.padding(.horizontal, 20)
}
}
}
enum Fruit: String, CaseIterable {
case apple = "Apple"
case grape = "Grape"
case lemon = "Lemon"
case orange = "Orange"
case peach = "Peach"
case pineapple = "Pineapple"
case watermelon = "Watermelon"
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
What I want to do is show the contextual menu when the user long-presses a fruit name, which works. Yet, if I long-press a child inside the disclosure view, I also get the contextual menu, which is unintentional. Is there a simple way by which I can stop the contextual menu to appear if long-press a child inside the disclosure view?
Muchos thankos
I have a ForEach loop with Range that I use with Picker. I'm using Range because I want to set startYear and endYear when View appears. The following is my code.
import SwiftUI
struct ProviderCalendarView: View {
@State private var startYear: Int = 2023
@State private var endYear: Int = 2034
@State private var selectedYear = 3
var body: some View {
VStack {
HStack {
Picker(selection: $selectedYear) {
ForEach((startYear...endYear), id: \.self) { year in
Text("\(year)")
}
} label: {
}
}
}
}
}
And the compiler says the following.
Picker: the selection "3" is invalid and does not have an associated tag, this will give undefined results.
It's not a critical error. But how can I stop it? Thanks.
I have a macOS application with SwiftUI. I am saving a dictionary containing two custom classes with NSSavePanel. That's not a problem.
import SwiftUI
struct ContentView: View {
var body: some View {
...
}
private func savePanel() -> URL? {
let savePanel = NSSavePanel()
savePanel.allowedContentTypes = [.myCustomeFileType]
savePanel.canCreateDirectories = true
savePanel.isExtensionHidden = false
savePanel.title = "Saving..."
savePanel.message = "Please select a path where to save a file."
savePanel.nameFieldStringValue = "Untitled"
return savePanel.runModal() == .OK ? savePanel.url : nil
}
private func fileSaveAs() {
if let url = savePanel() {
let models = colorViewModel.frameModels
let borderModel = BorderModel(showBorder: true, colorIndex: 6, borderWeightIndex: 8)
let dict = ["FrameModelArray": models, "BorderModel": borderModel] as [String : Any]
NSKeyedArchiver.setClassName("FrameModel", for: FrameModel.self)
NSKeyedArchiver.setClassName("BorderModel", for: BorderModel.self)
do {
let data = try NSKeyedArchiver.archivedData(withRootObject: dict, requiringSecureCoding: false)
try data.write(to: url, options: .atomic)
} catch {
print("Errrrrr \(error.localizedDescription)")
}
}
}
}
So my custom classes are FrameModel, BorderModel.
I can unarchive a saved file with a deprecated type method as follows.
private func fileOpen() {
if let url = openPanel() {
do {
NSKeyedUnarchiver.setClass(FrameModel.self, forClassName: "FrameModel")
NSKeyedUnarchiver.setClass(BorderModel.self, forClassName: "BorderModel")
let data = try Data(contentsOf: url)
if let someData = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) {
if let dict = someData as? [String : Any] {
if let frameModels = dict["FrameModelArray"] as? [FrameModel] {
print("[FrameModel] read...")
}
if let borderModel = dict["BorderModel"] as? BorderModel {
print("BorderModel read...")
}
}
}
} catch {
print("Errrrrr \(error.localizedDescription)")
}
}
}
If I use unarchivedObject(ofClasses:from:), I can't unarchive my file. What am I doing wrong? Thanks.
private func fileOpen() {
if let url = openPanel() {
do {
NSKeyedUnarchiver.setClass(FrameModel.self, forClassName: "FrameModel")
NSKeyedUnarchiver.setClass(BorderModel.self, forClassName: "BorderModel")
let data = try Data(contentsOf: url)
if let dictionary = try? NSKeyedUnarchiver.unarchivedObject(ofClasses: [FrameModel.self, BorderModel.self], from: data) as? NSDictionary {
print("Being read...")
} else {
print("Not read...")
}
} catch {
print("Errrrrr \(error.localizedDescription)")
}
}
}
When I enumerate an array of objects with ForEach, I often wonder how I use the array. For example, I have the following lines of code.
import SwiftUI
struct ContentView: View {
@State var checkItems: [CheckItem] = [
.init("Susan"),
.init("Meagan"),
.init("Daniel")
]
var body: some View {
List() {
ForEach(0..<checkItems.count, id: \.self) { index in
HStack {
Image(systemName: !checkItems[index].selected ? "circle" : "checkmark.circle.fill")
.resizable()
.scaledToFit()
.frame(height: 24)
.foregroundColor(!checkItems[index].selected ? .gray : .blue)
.onTapGesture {
checkItems[index].selected.toggle()
}
Text(checkItems[index].name)
}
}
}
}
}
struct CheckItem: Identifiable, Hashable {
var id = UUID()
var selected: Bool
var name: String
init(_ name: String) {
self.selected = false
self.name = name
}
}
The code works as shown in the following image.
In the following lines of code, I'm enumerating the same array in a slightly different fashion.
struct ContentView: View {
@State var checkItems: [CheckItem] = [
.init("Susan"),
.init("Meagan"),
.init("Daniel")
]
var body: some View {
List() {
ForEach(checkItems, id: \.id) { item in
HStack {
Image(systemName: !item.selected ? "circle" : "checkmark.circle.fill")
.resizable()
.scaledToFit()
.frame(height: 24)
.foregroundColor(!item.selected ? .gray : .blue)
.onTapGesture {
//item.selected.toggle() // Cannot use mutating member on immutable value: 'item' is a 'let' constant
}
Text(item.name)
}
}
}
}
}
And I get an error in the line inside the onTapGesture guy. I wonder why the first section of code works and why second section doesn't? Muchos thankos.
I've found a simple example at YouTube (https://www.youtube.com/watch?v=ddp1jwkDwr8) as to create a framework.
The following example does NOT use a framework.
import SwiftUI
struct ContentView: View {
@State private var selectedColor: Color = .clear
var body: some View {
VStack {
ColorSelectorView(selectedColor: $selectedColor) { color in
print("**** \(color)")
}
}
}
}
import SwiftUI
struct ColorSelectorView: View {
@Binding var selectedColor: Color
@State var callBack: ((Color) -> Void)?
let colors: [Color] = [.blue, .green, .orange, .yellow, .red, .purple]
var body: some View {
HStack {
ForEach(colors, id: \.self) { color in
Image(systemName: selectedColor == color ? "record.circle.fill" : "circle.fill")
.foregroundColor(color)
.onTapGesture {
selectedColor = color
callBack?(color)
}
}
}
}
}
#Preview {
ColorSelectorView(selectedColor: .constant(.red))
}
If I select a color, ContentView will receive a call back as to which color has been selected. So far, so good...
Now, I want to make the ColorSelectorView part a framework. ContentView doesn't change. The following is the framework part.
import SwiftUI
public struct ColorSelectorView: View {
@Binding var selectedColor: Color
@State var callBack: ((Color) -> Void)?
let colors: [Color] = [.blue, .green, .orange, .yellow, .red, .purple]
public init(selectedColor: Binding<Color>, callBack: ((Color) -> Void)? = nil) {
self._selectedColor = selectedColor
self.callBack = callBack
}
public var body: some View {
HStack {
ForEach(colors, id: \.self) { color in
Image(systemName: selectedColor == color ? "record.circle.fill" : "circle.fill")
.foregroundColor(color)
.onTapGesture {
selectedColor = color
callBack?(color)
}
}
}
}
}
struct ColorSelectorView_Previews: PreviewProvider {
static var previews: some View {
ColorSelectorView(selectedColor: .constant(.red))
}
}
Running ContentView with a framework, it doesn't receive a call back. What am I doing wrong? Muchos thankos.
I have a custom class named CodeReadModel, which contains another custom class named CodeDataModel. The former contains the latter as an array like the following.
class CodeReadModel: NSObject, NSSecureCoding {
class var supportsSecureCoding: Bool { true }
let identifier: String
let codeDataModels: [CodeDataModel]
init(identifier: String, codeDataModels: [CodeDataModel]) {
self.identifier = identifier
self.codeDataModels = codeDataModels
}
required init(coder decoder: NSCoder) {
self.identifier = decoder.decodeObject(forKey: "identifier") as! String
self.codeDataModels = decoder.decodeObject(forKey: "codeDataModels") as! [CodeDataModel]
}
func encode(with coder: NSCoder) {
coder.encode(identifier, forKey: "identifier")
coder.encode(codeDataModels, forKey: "codeDataModels")
}
}
And I want to unarchive an object with the following.
func importCodeReaderSnippetNext(fileURL: URL) {
do {
NSKeyedUnarchiver.setClass(CodeReadModel.self, forClassName: "CodeReadModel")
NSKeyedUnarchiver.setClass(CodeDataModel.self, forClassName: "CodeDataModel")
let data = try! Data(contentsOf: fileURL)
if let codeReadModel = try NSKeyedUnarchiver.unarchivedObject(ofClass: CodeReadModel.self, from: data) {
}
} catch {
print("Error: \(error.localizedDescription)")
}
}
And I will get an error because codeReadModel contains another custom class, which cannot be decoded. How can I resolve this problem? Muchas thankos.
I'm showing a Text View when a button with an image is long-pressed.
import SwiftUI
struct ContentView: View {
@Environment(\.colorScheme) var colorScheme
var isDark: Bool {
return colorScheme == .dark
}
@State private var showLabel = false
var body: some View {
Button(action: {
}) {
VStack {
ZStack {
Image(systemName: "swift")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 32)
.padding(.horizontal, 40)
.padding(.vertical, 6)
.background(.gray.opacity(0.2), in: RoundedRectangle(cornerRadius: 10))
.onTapGesture {
showLabel.toggle()
}
.onLongPressGesture(minimumDuration: 2) {
print("Long pressed...")
showLabel.toggle()
}
if showLabel {
Text("Help Content")
.font(.caption)
.foregroundStyle(!isDark ? .white : .black)
.padding(10)
.background(!isDark ? .black : .white, in: Rectangle())
.onTapGesture {
print("hey")
showLabel.toggle()
}
.offset(x: 120)
}
}
}
}
}
}
So a Text View will appear as shown in the image above. But its .onTapGesture is never called. I wonder why? Thanks.
I'm using NSTableView with NSViewRepresentable in my SwiftUI ContentView. I'm letting the user right-click on a table row such that the application will recognize the row number, which is achieved. The following is what I have so far.
struct ContentView: View {
@State private var rowSelection = -1
VStack {
TableView(tableData: someData, selectedRow: $rowSelection)
}
}
struct TableView: NSViewRepresentable {
@Binding var tableData: [Dictionary<String, String>]
@Binding var selectedRow: Int
func makeNSView(context: Context) -> NSScrollView {
let scrollView = NSScrollView(frame: .zero)
let tableView = NSTableView()
tableView.delegate = context.coordinator
tableView.dataSource = context.coordinator
let contextMenu = NSMenu()
let copyRowMenuItem = NSMenuItem(title: "Copy Row", action: #selector(Coordinator.tableRowAction(_:)), keyEquivalent: "")
contextMenu.addItem(copyRowMenuItem)
copyRowMenuItem.target = context.coordinator
tableView.menu = contextMenu
scrollView.documentView = tableView
scrollView.hasVerticalScroller = true
scrollView.hasHorizontalScroller = true
scrollView.autohidesScrollers = true
return scrollView
}
func updateNSView(_ nsView: NSScrollView, context: Context) {
}
func makeCoordinator() -> Coordinator {
return Coordinator(tableData: $tableData, tableInfo: $tableInfo, selectedRow: $selectedRow, rowSelected: $rowSelected)
}
class Coordinator: NSObject, NSTableViewDelegate, NSTableViewDataSource {
@Binding var tableData: [Dictionary<String, String>]
@Binding var selectedRow: Int
init(tableData: Binding<[Dictionary<String, String>]>, tableInfo: Binding<[PragmaModel]>, selectedRow: Binding<Int>, rowSelected: Binding<Bool>) {
self._tableData = tableData
self._rowSelected = rowSelected
}
func numberOfRows(in tableView: NSTableView) -> Int {
return tableData.count
}
func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? {
for i in 0..<tableInfo.count {
let col = NSString(format: "%i", i) as String
let identifier = NSString(format: "Column%i", i) as String
if ((tableColumn?.identifier)!.rawValue == identifier) {
let data = tableData[row][col]
return data
}
}
return nil
}
func tableViewSelectionDidChange(_ notification: Notification) {
let tv = notification.object as! NSTableView
if tv.selectedRow >= 0 {
selectedRow = tv.selectedRow
}
}
@objc func tableRowAction(_ sender: Any) {
// closure //
}
}
}
The contextual menu works. Yet, the application needs to know when a row is clicked on. So I want to send a closure back to ContentView. How can I do that, por favor? Muchos thankos.
I'm trying to set the background color of a button with label like the following for a macOS application. I haven't run it for iOS.
VStack(spacing: 20) {
HStack(spacing: 32) {
Button {
showGuide.toggle()
} label: {
Text("Hello")
.font(.title3)
.frame(width: 190, height: 36)
}
.foregroundStyle(.primary)
.background(.yellow)
.clipShape(.capsule)
.shadow(color: .red, radius: 8)
Button {
} label: {
Text("Good morning")
.font(.title3)
.frame(width: 190, height: 36)
}
.foregroundStyle(.primary)
.background(.pink)
.clipShape(.capsule)
.shadow(color: .red, radius: 8)
}
}
.frame(maxWidth: .infinity, alignment: .center)
Interestingly, those two buttons have a white background color under the light appearance as shown below.
And it will get the designated background color under the dark appearance as shown below.
So why don't I get the buttons colored under the light appearance? I can't figure out why it happens. Does anybody know why? Thanks.