Skip to content

Commit a08139b

Browse files
committed
feat(ocr): optimize clipboard image handling and memory management during OCR processing
1 parent a4853e3 commit a08139b

14 files changed

Lines changed: 41 additions & 21 deletions

Sources/Core/OCR/ScreenCaptureOCR.swift

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,16 @@ enum ScreenCaptureOCR {
2828
throw OCRError.captureCancelled
2929
}
3030

31-
// Read image from clipboard
32-
let pasteboard = NSPasteboard.general
33-
guard let image = NSImage(pasteboard: pasteboard),
34-
let cgImage = image.cgImage(forProposedRect: nil, context: nil, hints: nil)
35-
else {
36-
throw OCRError.noImageInClipboard
31+
// Read image from clipboard and perform OCR inside autoreleasepool
32+
// to ensure large screenshot images are freed promptly.
33+
let cgImage: CGImage = try autoreleasepool {
34+
let pasteboard = NSPasteboard.general
35+
guard let image = NSImage(pasteboard: pasteboard),
36+
let cg = image.cgImage(forProposedRect: nil, context: nil, hints: nil)
37+
else {
38+
throw OCRError.noImageInClipboard
39+
}
40+
return cg
3741
}
3842

3943
return try await recognizeText(in: cgImage)

Sources/Services/Providers/AppleTranslationProvider.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ struct AppleTranslationProvider: TranslationProvider {
9595
windowRef.value = window
9696

9797
if Task.isCancelled {
98+
window.contentView = nil
9899
window.close()
99100
continuation.resume(throwing: CancellationError())
100101
return

Sources/Services/Providers/BaiduTranslateProvider.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ struct BaiduTranslateProvider: TranslationProvider {
6666
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
6767
request.httpBody = formParts.joined(separator: "&").data(using: .utf8)
6868

69-
let (data, response) = try await URLSession.shared.data(for: request)
69+
let (data, response) = try await translationURLSession.data(for: request)
7070

7171
guard let httpResponse = response as? HTTPURLResponse else {
7272
throw TranslationError.invalidResponse

Sources/Services/Providers/BingTranslateProvider.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ struct BingTranslateProvider: TranslationProvider {
6767
request.setValue("https://www.bing.com/translator", forHTTPHeaderField: "Referer")
6868
request.httpBody = formBody.data(using: .utf8)
6969

70-
let (data, response) = try await URLSession.shared.data(for: request)
70+
let (data, response) = try await translationURLSession.data(for: request)
7171

7272
guard let httpResponse = response as? HTTPURLResponse else {
7373
throw TranslationError.invalidResponse
@@ -160,7 +160,7 @@ private actor BingTokenManager {
160160
request.timeoutInterval = 15
161161
request.setValue(Self.userAgent, forHTTPHeaderField: "User-Agent")
162162

163-
let (data, response) = try await URLSession.shared.data(for: request)
163+
let (data, response) = try await translationURLSession.data(for: request)
164164

165165
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
166166
throw TranslationError.apiError(

Sources/Services/Providers/CaiyunProvider.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ struct CaiyunProvider: TranslationProvider {
7070
request.setValue("token \(token)", forHTTPHeaderField: "x-authorization")
7171
request.httpBody = try JSONSerialization.data(withJSONObject: body)
7272

73-
let (data, response) = try await URLSession.shared.data(for: request)
73+
let (data, response) = try await translationURLSession.data(for: request)
7474

7575
guard let httpResponse = response as? HTTPURLResponse else {
7676
throw TranslationError.invalidResponse

Sources/Services/Providers/DeepLProvider.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ struct DeepLProvider: TranslationProvider {
6161
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
6262
request.httpBody = formParts.joined(separator: "&").data(using: .utf8)
6363

64-
let (data, response) = try await URLSession.shared.data(for: request)
64+
let (data, response) = try await translationURLSession.data(for: request)
6565

6666
guard let httpResponse = response as? HTTPURLResponse else {
6767
throw TranslationError.invalidResponse

Sources/Services/Providers/GoogleTranslateProvider.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ struct GoogleTranslateProvider: TranslationProvider {
5656
forHTTPHeaderField: "User-Agent"
5757
)
5858

59-
let (data, response) = try await URLSession.shared.data(for: request)
59+
let (data, response) = try await translationURLSession.data(for: request)
6060

6161
guard let httpResponse = response as? HTTPURLResponse else {
6262
throw TranslationError.invalidResponse

Sources/Services/Providers/NiuTransProvider.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ struct NiuTransProvider: TranslationProvider {
5555
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
5656
request.httpBody = formParts.joined(separator: "&").data(using: .utf8)
5757

58-
let (data, response) = try await URLSession.shared.data(for: request)
58+
let (data, response) = try await translationURLSession.data(for: request)
5959

6060
guard let httpResponse = response as? HTTPURLResponse else {
6161
throw TranslationError.invalidResponse

Sources/Services/Providers/OllamaProvider.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ struct OllamaProvider: TranslationProvider {
6565
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
6666
request.httpBody = try JSONSerialization.data(withJSONObject: body)
6767

68-
let (bytes, response) = try await URLSession.shared.bytes(for: request)
68+
let (bytes, response) = try await translationURLSession.bytes(for: request)
6969
try await streamOpenAISSE(bytes, response: response, to: continuation)
7070
continuation.finish()
7171
} catch let error as URLError where error.code == .cannotConnectToHost || error.code == .timedOut {
@@ -95,7 +95,7 @@ struct OllamaProvider: TranslationProvider {
9595
var request = URLRequest(url: url)
9696
request.timeoutInterval = 5
9797

98-
let (data, response) = try await URLSession.shared.data(for: request)
98+
let (data, response) = try await translationURLSession.data(for: request)
9999

100100
guard let httpResponse = response as? HTTPURLResponse else {
101101
throw TranslationError.invalidResponse
@@ -246,7 +246,7 @@ private struct OllamaSettingsView: View {
246246
var request = URLRequest(url: pingURL)
247247
request.timeoutInterval = 3
248248
do {
249-
let (_, response) = try await URLSession.shared.data(for: request)
249+
let (_, response) = try await translationURLSession.data(for: request)
250250
if let http = response as? HTTPURLResponse, http.statusCode == 200 {
251251
serverStatus = .running
252252
} else {

Sources/Services/Providers/OpenAICompatibleProvider.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ struct OpenAICompatibleProvider: TranslationProvider {
5252
let task = Task {
5353
do {
5454
let request = try buildRequest(text: text, sourceLang: sourceLang, targetLang: targetLang)
55-
let (bytes, response) = try await URLSession.shared.bytes(for: request)
55+
let (bytes, response) = try await translationURLSession.bytes(for: request)
5656
try await streamOpenAISSE(bytes, response: response, to: continuation)
5757
continuation.finish()
5858
} catch {

0 commit comments

Comments
 (0)