Post

Replies

Boosts

Views

Activity

Reply to AppleScript "Image Events" does no longer get all Metadata
I did another test using a small sample based on https://stackoverflow.com/questions/18265760/get-exif-data-in-mac-os-development. I wrote a simple console App with following code: #import <Foundation/Foundation.h> #import <ImageIO/ImageIO.h> int main(int argc, const char * argv[]) {     @autoreleasepool {         NSURL *imageFileURL = [NSURL fileURLWithPath: [@"~/Desktop/IMG_1845.HEIC" stringByStandardizingPath]];         CGImageSourceRef imageSource = CGImageSourceCreateWithURL((CFURLRef)imageFileURL, NULL);         NSDictionary *treeDict;         NSMutableString *exifData;         NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO], (NSString *)kCGImageSourceShouldCache, nil];         CFDictionaryRef imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, ( CFDictionaryRef)options);         CFRelease(imageSource);         if (imageProperties) {             treeDict = [NSDictionary dictionaryWithDictionary:(__bridge NSDictionary*)(imageProperties)];             id exifTree = [treeDict objectForKey:@"{Exif}"];             exifData = [NSMutableString stringWithString:@""];             for (NSString *key in [[exifTree allKeys] sortedArrayUsingSelector:@selector(compare:)])             {                 NSString* locKey = [[NSBundle bundleWithIdentifier:@"com.apple.ImageIO.framework"] localizedStringForKey:key value:key table: @"CGImageSource"];                 id  value = [exifTree  valueForKey:key];                 [exifData appendFormat:@"key =%@ ; Value = %@ \n", locKey,value];             }             NSLog(@" exifData %@", exifData);         }         return 0;     } } On macOS 14.6 I get following output: $ ./exifTest 2023-01-25 09:44:32.532 exifTest[2409:21024] exifData key =Aperture Value ; Value = 1.169925002106682 key =Brightness Value ; Value = 4.710561089652368 key =Color Space ; Value = 65535 key =Date Time Digitized ; Value = 2022:10:27 16:31:42 key =Date Time Original ; Value = 2022:10:27 16:31:42 key =Digital Zoom Ratio ; Value = 1.2096 key =Exif Version ; Value = ( 2, 3, 2 ) key =Exposure Bias Value ; Value = 0 key =Exposure Mode ; Value = 0 key =Exposure Program ; Value = 2 key =Exposure Time ; Value = 0.00684931506849315 key =FNumber ; Value = 1.5 key =Flash ; Value = 16 key =Focal Length In 35mm Film ; Value = 31 key =Focal Length ; Value = 5.7 key =ISO Speed Ratings ; Value = ( 64 ) key =Lens Make ; Value = Apple key =Lens Model ; Value = iPhone 14 back dual wide camera 5.7mm f/1.5 key =Lens Specification ; Value = ( "1.54", "5.7", "1.5", "2.4" ) key =Metering Mode ; Value = 5 key =Pixel X Dimension ; Value = 4032 key =Pixel Y Dimension ; Value = 3024 key =Scene Type ; Value = 1 key =Sensing Method ; Value = 2 key =Shutter Speed Value ; Value = 7.185264202431158 key =Subject Area ; Value = ( 2016, 1508, 2319, 1327 ) key =Sub-second Time Digitized ; Value = 305 key =Sub-second Time Original ; Value = 305 key =White Balance ; Value = 0 on macOS 13.2 I get $ ./exifTest 2023-01-25 09:37:19.219 exifTest[21828:415974] exifData key =(null) ; Value = 1.169925002106682 key =(null) ; Value = 4.710561089652368 key =(null) ; Value = 65535 key =(null) ; Value = 2 key =(null) ; Value = 2022:10:27 16:31:42 key =(null) ; Value = 2022:10:27 16:31:42 key =(null) ; Value = 1.2096 key =(null) ; Value = ( 2, 3, 2 ) key =(null) ; Value = 0 key =(null) ; Value = 0 key =(null) ; Value = 2 key =(null) ; Value = 0.00684931506849315 key =(null) ; Value = 1.5 key =(null) ; Value = 16 key =(null) ; Value = 31 key =(null) ; Value = 5.7 key =(null) ; Value = ( 64 ) key =(null) ; Value = Apple key =(null) ; Value = iPhone 14 back dual wide camera 5.7mm f/1.5 key =(null) ; Value = ( "1.54", "5.7", "1.5", "2.4" ) key =(null) ; Value = 5 key =(null) ; Value = +02:00 key =(null) ; Value = +02:00 key =(null) ; Value = +02:00 key =(null) ; Value = 4032 key =(null) ; Value = 3024 key =(null) ; Value = 1 key =(null) ; Value = 2 key =(null) ; Value = 7.185264202431158 key =(null) ; Value = ( 2016, 1508, 2319, 1327 ) key =(null) ; Value = 305 key =(null) ; Value = 305 key =(null) ; Value = 0 So it seems that the EXIF keys are no longer provided from the OS!
Jan ’23
Reply to Fatal error: Duplicate keys of type 'SOMETYPE' were found in a Dictionary.
Where do you call updateVorlesung ? I show a separate data-entry Window and I call it in a Button("Ok").action. The Class Vorlesung is Hashable: func hash(into hasher: inout Hasher) { hasher.combine(vID) // UUID } The debug output of the class properties and the Hash does not show a duplicate hash value. It is also very unlikely that there is a duplicate hash because of the used UUID… Any other ideas how to solve this?
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Mar ’23
Reply to Fatal error: Duplicate keys of type 'SOMETYPE' were found in a Dictionary.
Tested right now. No difference. The error message is 2023-03-16 08:06:52.903332+0100 ITR-Stundenplan[91211:778159] Fatal error: Duplicate keys of type 'Vorlesung' were found in a Dictionary. This usually means either that the type violates Hashable's requirements, or that members of such a dictionary were mutated after insertion. I wonder if there is perhaps a timing issue, where the data is accessed during the change although I use objectWillChange: self.objectWillChange.send() self.vorlesungen = newList Really strange…
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Mar ’23
Reply to Fatal error: Duplicate keys of type 'SOMETYPE' were found in a Dictionary.
Now I was able to build a simplified example which shows the error. I have two days and a click on the button does send it to the other day and back. It does sometimes crash on the first call but on another run on the 3rd call. I post the code below. Perhaps it gives a clue what's wrong: import SwiftUI enum Weekdays : String, CaseIterable { case Montag case Dienstag case Mittwoch case Donnerstag case Freitag case Samstag //case Sonntag } class Vorlesung : Hashable, Equatable, Identifiable, ObservableObject { @Published var subject : String @Published var day : Weekdays let vID = UUID() init(subject: String, day : Weekdays) { self.subject = subject self.day = day } static func == (lhs: Vorlesung, rhs: Vorlesung) -> Bool { let result = lhs.subject.compare(rhs.subject) == .orderedSame return result } func hash(into hasher: inout Hasher) { hasher.combine(vID) // UUID } } public class VorlesungsHandler : ObservableObject { let dayList : [Weekdays] = [.Montag, .Dienstag]//, .Mittwoch, .Donnerstag, .Freitag] @Published var vorlesungen : [Vorlesung] = [ Vorlesung(subject: "banana", day: .Montag), Vorlesung(subject: "strawberry", day: .Montag), Vorlesung(subject: "apple", day: .Montag), Vorlesung(subject: "pear", day: .Montag) ] func updateVorlesung(oldID : UUID?, newV : Vorlesung) { self.vorlesungen.removeAll { value in value.vID == oldID } self.vorlesungen.append(newV) } } struct PlanEntryView: View { @EnvironmentObject var appData : VorlesungsHandler @ObservedObject var setup : Vorlesung @State private var showDataView : Bool = false var body: some View { ZStack { Button(setup.subject) { let switchedDay : Weekdays = setup.day == .Montag ? .Dienstag : .Montag appData.updateVorlesung(oldID: setup.vID, newV: Vorlesung(subject: setup.subject, day: switchedDay)) } } } } struct RoomView: View { @EnvironmentObject var appData : VorlesungsHandler var day : Weekdays var body: some View { VStack() { VStack { ForEach(appData.vorlesungen, id: \.self) { value in if (value.day == day) { PlanEntryView(setup: value) .environmentObject(appData) } } } } } } struct DayView: View { @EnvironmentObject var appData : VorlesungsHandler var day : Weekdays var body: some View { VStack { Text(day.rawValue) HStack { RoomView(day: day) .environmentObject(appData) } Spacer() } } } struct ContentView: View { @EnvironmentObject var appData : VorlesungsHandler var body: some View { VStack { ForEach(appData.dayList, id: \.self) { value in DayView(day: value) .environmentObject(appData) } } } } struct ContentView_Previews: PreviewProvider { @StateObject static var previewData = VorlesungsHandler() static var previews: some View { ContentView() .environmentObject(previewData) } } @main struct crasherApp: App { @StateObject private var appData = VorlesungsHandler() var body: some Scene { WindowGroup { ContentView() .environmentObject(appData) } } }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Mar ’23
Reply to Fatal error: Duplicate keys of type 'SOMETYPE' were found in a Dictionary.
I did post the same question on Swift Forum and got a solution: Currently your hash and == are using completely different properties, which leads to conflict between them. Are two Vorlesung with the same subject but different vID equal to each other, or not? According to == they are equal, but according to hash they are not. We need to fix that You need to decide what makes two Vorlesung the same, and use these properties in both == and hash. Usually in a struct it's all of the properties, and that's handled by the autogenerated implementation so a change in my code did solve the issue: static func == (lhs: Vorlesung, rhs: Vorlesung) -> Bool { let result = lhs.subject.compare(rhs.subject) == .orderedSame return result } func hash(into hasher: inout Hasher) { hasher.combine(subject) }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Mar ’23
Reply to Random SwiftUI crashes
Now I was able to build a (not so small) example which shows the issue. It shows two rectangles which can be selected. After selection it is possible to move them via the toolbar buttons. Click a rectangle and move it up and down. Change selection and repeat. After some tries it will crash. I post the example in the next post because the message size limit is reached.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Mar ’23
Reply to Random SwiftUI crashes
import SwiftUI struct vTime : Codable { var hour : Int var min : Int } struct RecDate : Codable { var day : Int var start: vTime var end : vTime private enum CodingKeys : String, CodingKey { case day case start case end } func duration() -> CGFloat { let dTime : CGFloat = abs(CGFloat(end.hour - start.hour) * 4.0 + CGFloat(end.min - start.min) / 15.0) return dTime } } class Record : Hashable, Equatable, Identifiable, ObservableObject { let vID = UUID() @Published var subject : String @Published var date : RecDate init(subject: String, date : RecDate) { self.subject = subject self.date = date } static func == (lhs: Record, rhs: Record) -> Bool { var r = lhs.subject.compare(rhs.subject) == .orderedSame r = r && lhs.date.start.hour == rhs.date.start.hour r = r && lhs.date.start.min == rhs.date.start.min r = r && lhs.date.end.hour == rhs.date.end.hour r = r && lhs.date.end.min == rhs.date.end.min r = r && lhs.vID == rhs.vID return r } func hash(into hasher: inout Hasher) { hasher.combine(subject) hasher.combine(date.start.hour) hasher.combine(date.start.min) hasher.combine(date.end.hour) hasher.combine(date.end.min) hasher.combine(vID) } func isSelected(appSelection : UUID?) -> Bool { return appSelection == vID } public func incDate() { if !(self.date.end.hour == 19 && self.date.end.min == 0) { self.date.start.min += 15 self.date.end.min += 15 if self.date.start.min == 60 { self.date.start.min = 0 self.date.start.hour += 1 } if self.date.end.min == 60 { self.date.end.min = 0 self.date.end.hour += 1 } } } public func decDate() { if !(self.date.start.hour == 8 && self.date.start.min == 0) { self.date.start.min -= 15 self.date.end.min -= 15 if self.date.start.min < 0 { self.date.start.min = 45 self.date.start.hour -= 1 } if self.date.end.min < 0 { self.date.end.min = 45 self.date.end.hour -= 1 } } } } public class RecordHandler : ObservableObject { @Published var records : [Record] = [ Record(subject: "banana", date: RecDate(day: 0, start: vTime(hour: 8, min: 0), end: vTime(hour: 10, min: 0))), Record(subject: "strawberry", date: RecDate(day: 1, start: vTime(hour: 11, min: 0), end: vTime(hour: 14, min: 0))) ] @Published var selectedID : UUID? = nil func updateRecord(oldID : UUID?, newV : Record) { self.records.removeAll { value in value.vID == oldID } self.records.append(newV) } func setSel(newID : UUID) { if selectedID == nil { selectedID = newID } else { if selectedID == newID { selectedID = nil } else { selectedID = newID } } } } struct EntryView: View { @EnvironmentObject var appData : RecordHandler @ObservedObject var setup : Record @State private var showDataView : Bool = false struct SelView : View { var body: some View { ZStack { Rectangle() .inset(by: -2) .stroke(.blue, lineWidth: 5.0) } } } var body: some View { let qCount = setup.date.duration() let height = qCount * 10.0 let xPos = 100.0 let yPos = 7.0 + (CGFloat(setup.date.start.hour) - 8.0) * 40.0 + CGFloat(setup.date.start.min) / 1.5 + (qCount - 1.0) * 5.0 ZStack { RoundedRectangle(cornerRadius: 10) .foregroundColor(.red.opacity(0.80)) VStack { Text(setup.subject) .bold() .allowsTightening(true) .multilineTextAlignment(.center) .truncationMode(.tail) } .font(.system(size: 10)) .padding([.leading, .trailing], 5) if setup.isSelected(appSelection: appData.selectedID) { SelView() } } .frame(width: 200, height: height) .position(x: xPos, y: yPos) .onTapGesture(count: 1) { appData.setSel(newID: setup.vID) } } } struct RoomView: View { @EnvironmentObject var appData : RecordHandler var body: some View { VStack() { VStack { ForEach(appData.records, id: \.self) { value in EntryView(setup: value) .environmentObject(appData) } } } } } struct DayView: View { @EnvironmentObject var appData : RecordHandler var day : Int var body: some View { VStack { ForEach(appData.records, id: \.self) { value in if value.date.day == day { EntryView(setup: value) .environmentObject(appData) } } } } } struct ContentView: View { @EnvironmentObject var appData : RecordHandler var body: some View { NavigationStack { HStack { DayView(day: 0) .environmentObject(appData) DayView(day: 1) .environmentObject(appData) } } .toolbar { ToolbarItemGroup(placement: .automatic) { Button("↑") { if let ds = appData.records.first(where: { $0.vID == appData.selectedID!}) { ds.decDate() } } .disabled(appData.selectedID == nil) Button("↓") { if let ds = appData.records.first(where: { $0.vID == appData.selectedID!}) { ds.incDate() } } .disabled(appData.selectedID == nil) } } } } struct ContentView_Previews: PreviewProvider { @StateObject static var previewData = RecordHandler() static var previews: some View { ContentView() .environmentObject(previewData) } } @main struct crasherApp: App { @StateObject private var appData = RecordHandler() var body: some Scene { WindowGroup { ContentView() .environmentObject(appData) } } }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Mar ’23
Reply to Random SwiftUI crashes
Here is a smaller version which does also crash (now tested with new Xcode 14.3): import SwiftUI struct vTime : Codable { var hour : Int var min : Int } struct RecDate : Codable { var day : Int var start: vTime var end : vTime private enum CodingKeys : String, CodingKey { case day case start case end } func duration() -> CGFloat { let dTime : CGFloat = abs(CGFloat(end.hour - start.hour) * 4.0 + CGFloat(end.min - start.min) / 15.0) return dTime } } class Record : Hashable, Equatable, Identifiable, ObservableObject { let vID = UUID() @Published var subject : String @Published var date : RecDate init(subject: String, date : RecDate) { self.subject = subject self.date = date } static func == (lhs: Record, rhs: Record) -> Bool { var r = lhs.subject.compare(rhs.subject) == .orderedSame r = r && lhs.date.start.hour == rhs.date.start.hour r = r && lhs.date.start.min == rhs.date.start.min r = r && lhs.date.end.hour == rhs.date.end.hour r = r && lhs.date.end.min == rhs.date.end.min r = r && lhs.vID == rhs.vID return r } func hash(into hasher: inout Hasher) { hasher.combine(subject) hasher.combine(date.start.hour) hasher.combine(date.start.min) hasher.combine(date.end.hour) hasher.combine(date.end.min) hasher.combine(vID) } func isSelected(appSelection : UUID?) -> Bool { return appSelection == vID } public func incDate() { if !(self.date.end.hour == 19 && self.date.end.min == 0) { self.date.start.min += 15 self.date.end.min += 15 if self.date.start.min == 60 { self.date.start.min = 0 self.date.start.hour += 1 } if self.date.end.min == 60 { self.date.end.min = 0 self.date.end.hour += 1 } } } public func decDate() { if !(self.date.start.hour == 8 && self.date.start.min == 0) { self.date.start.min -= 15 self.date.end.min -= 15 if self.date.start.min < 0 { self.date.start.min = 45 self.date.start.hour -= 1 } if self.date.end.min < 0 { self.date.end.min = 45 self.date.end.hour -= 1 } } } } public class RecordHandler : ObservableObject { @Published var records : [Record] = [ Record(subject: "banana", date: RecDate(day: 0, start: vTime(hour: 8, min: 0), end: vTime(hour: 10, min: 0))), Record(subject: "strawberry", date: RecDate(day: 1, start: vTime(hour: 11, min: 0), end: vTime(hour: 14, min: 0))) ] @Published var selectedID : UUID? = nil func setSel(newID : UUID) { if selectedID == nil { selectedID = newID } else { if selectedID == newID { selectedID = nil } else { selectedID = newID } } } } struct EntryView: View { @EnvironmentObject var appData : RecordHandler @ObservedObject var setup : Record @State private var showDataView : Bool = false struct SelView : View { var body: some View { Rectangle() .inset(by: -2) .stroke(.blue, lineWidth: 5.0) } } var body: some View { let qCount = setup.date.duration() let height = qCount * 10.0 let xPos = 100.0 let yPos = 7.0 + (CGFloat(setup.date.start.hour) - 8.0) * 40.0 + CGFloat(setup.date.start.min) / 1.5 + (qCount - 1.0) * 5.0 ZStack { RoundedRectangle(cornerRadius: 10) .foregroundColor(.red.opacity(0.80)) Text(setup.subject) if setup.isSelected(appSelection: appData.selectedID) { SelView() } } .frame(width: 200, height: height) .position(x: xPos, y: yPos) .onTapGesture(count: 1) { appData.setSel(newID: setup.vID) } } } struct DayView: View { @EnvironmentObject var appData : RecordHandler var day : Int var body: some View { VStack { ForEach(appData.records, id: \.self) { value in if value.date.day == day { EntryView(setup: value) .environmentObject(appData) } } } } } struct ContentView: View { @EnvironmentObject var appData : RecordHandler var body: some View { NavigationStack { HStack { DayView(day: 0) .environmentObject(appData) DayView(day: 1) .environmentObject(appData) } } .toolbar { ToolbarItemGroup(placement: .automatic) { Button("↑") { if let ds = appData.records.first(where: { $0.vID == appData.selectedID!}) { ds.decDate() } } .disabled(appData.selectedID == nil) Button("↓") { if let ds = appData.records.first(where: { $0.vID == appData.selectedID!}) { ds.incDate() } } .disabled(appData.selectedID == nil) } } } } struct ContentView_Previews: PreviewProvider { @StateObject static var previewData = RecordHandler() static var previews: some View { ContentView() .environmentObject(previewData) } } @main struct crasherApp: App { @StateObject private var appData = RecordHandler() var body: some Scene { WindowGroup { ContentView() .environmentObject(appData) } } }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Mar ’23
Reply to Swift Regex too slow als grep replacement?
The Swift code is fast for everything but the RegEx. The file read takes about 1 s but the RegEx takes more than 80 s. That's why I ask for help to speed-up the RegEx. My Swift sample code does no sort and uniq as in the shell example. This will be added after the RegEx is usable. I won´t care if the code in not quite so fast as my shell but it must be much quicker to be usable.
Topic: Programming Languages SubTopic: Swift Tags:
Jun ’23