Browse Source

Improved code

Signed-off-by: Marino Faggiana <marino@marinofaggiana.com>
Marino Faggiana 2 years ago
parent
commit
6527e69523

+ 4 - 0
Nextcloud.xcodeproj/project.pbxproj

@@ -436,6 +436,7 @@
 		F7A8D74528F1828E008BBE1C /* CCUtility.m in Sources */ = {isa = PBXBuildFile; fileRef = F7053E3D1C639DF500741EA5 /* CCUtility.m */; };
 		F7AC1CB028AB94490032D99F /* Array+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7AC1CAF28AB94490032D99F /* Array+Extension.swift */; };
 		F7AC934A296193050002BC0F /* Reasons to use Nextcloud.pdf in Resources */ = {isa = PBXBuildFile; fileRef = F7AC9349296193050002BC0F /* Reasons to use Nextcloud.pdf */; };
+		F7AC934C2962DF050002BC0F /* FontSizeCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7AC934B2962DF050002BC0F /* FontSizeCalculator.swift */; };
 		F7AE00F5230D5F9E007ACF8A /* NCLoginWeb.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7AE00F4230D5F9E007ACF8A /* NCLoginWeb.swift */; };
 		F7AE00F8230E81CB007ACF8A /* NCBrowserWeb.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7AE00F7230E81CB007ACF8A /* NCBrowserWeb.swift */; };
 		F7AE00FA230E81EB007ACF8A /* NCBrowserWeb.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7AE00F9230E81EB007ACF8A /* NCBrowserWeb.storyboard */; };
@@ -1025,6 +1026,7 @@
 		F7AA41E127C7CF8100494705 /* es-MX */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "es-MX"; path = "es-MX.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
 		F7AC1CAF28AB94490032D99F /* Array+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+Extension.swift"; sourceTree = "<group>"; };
 		F7AC9349296193050002BC0F /* Reasons to use Nextcloud.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = "Reasons to use Nextcloud.pdf"; sourceTree = SOURCE_ROOT; };
+		F7AC934B2962DF050002BC0F /* FontSizeCalculator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FontSizeCalculator.swift; sourceTree = "<group>"; };
 		F7ACE4291BAC0268006C0017 /* Acknowledgements.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Acknowledgements.h; sourceTree = "<group>"; };
 		F7ACE42A1BAC0268006C0017 /* Acknowledgements.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Acknowledgements.m; sourceTree = "<group>"; };
 		F7ACE42B1BAC0268006C0017 /* Acknowledgements.rtf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.rtf; path = Acknowledgements.rtf; sourceTree = "<group>"; };
@@ -1900,6 +1902,7 @@
 				F70BFC7320E0FA7C00C67599 /* NCUtility.swift */,
 				AF93474B27E34120002537EE /* NCUtility+Image.swift */,
 				F74AF3A3247FB6AE00AC767B /* NCUtilityFileSystem.swift */,
+				F7AC934B2962DF050002BC0F /* FontSizeCalculator.swift */,
 				AF36077027BFA4E8001A243D /* ParallelWorker.swift */,
 				F7245923289BB50B00474787 /* ThreadSafeDictionary.swift */,
 			);
@@ -3113,6 +3116,7 @@
 				F73D5E47246DE09200DF6467 /* NCElementsJSON.swift in Sources */,
 				F710D1F52405770F00A6033D /* NCViewerPDF.swift in Sources */,
 				F7B6B70427C4E7FA00A7F6EB /* NCScan+CollectionView.swift in Sources */,
+				F7AC934C2962DF050002BC0F /* FontSizeCalculator.swift in Sources */,
 				F7C30DF6291BC0CA0017149B /* NCNetworkingE2EEUpload.swift in Sources */,
 				F7501C332212E57500FB1415 /* NCMedia.swift in Sources */,
 				F70BFC7420E0FA7D00C67599 /* NCUtility.swift in Sources */,

+ 7 - 9
iOSClient/Main/Create cloud/NCUploadScanDocument.swift

@@ -101,10 +101,6 @@ class NCUploadScanDocument: ObservableObject {
 
         let fileNamePath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)!
         let pdfData = NSMutableData()
-        var fontColor = UIColor.clear
-#if targetEnvironment(simulator)
-        fontColor = UIColor.red
-#endif
 
         if password.isEmpty {
             UIGraphicsBeginPDFContextToData(pdfData, CGRect.zero, nil)
@@ -149,8 +145,9 @@ class NCUploadScanDocument: ObservableObject {
                         let rect = observation.boundingBox.applying(t)
                         let text = textLine.string
 
-                        let font = UIFont.systemFont(ofSize: rect.size.height, weight: .regular)
-                        let attributes = self.bestFittingFont(for: text, in: rect, fontDescriptor: font.fontDescriptor, fontColor: fontColor)
+                        let fontSize = FontSizeCalculator.shared.fontSizeThatFits(text: text, rectSize: rect.size)
+                        let font = UIFont.systemFont(ofSize: fontSize)
+                        let attributes = self.bestFittingFont(for: text, in: rect, fontDescriptor: font.fontDescriptor, fontColor: UIColor.clear)
 
                         text.draw(with: rect, options: .usesLineFragmentOrigin, attributes: attributes, context: nil)
                     }
@@ -178,7 +175,7 @@ class NCUploadScanDocument: ObservableObject {
         }
     }
 
-    func createPDFPreview(quality: Double) -> Data {
+    func createPDFPreview(quality: Double, isTextRecognition: Bool) -> Data {
 
         if var image = images.first {
 
@@ -425,7 +422,7 @@ struct UploadScanDocumentView: View {
                         })
                         .accentColor(Color(NCBrandColor.shared.brand))
                     }
-                    PDFKitRepresentedView(quality: $quality, uploadScanDocument: uploadScanDocument)
+                    PDFKitRepresentedView(quality: $quality, isTextRecognition: $isTextRecognition, uploadScanDocument: uploadScanDocument)
                         .frame(maxWidth: .infinity, minHeight: geo.size.height / 2.6)
                 }.complexModifier { view in
                     if #available(iOS 15, *) {
@@ -525,6 +522,7 @@ struct PDFKitRepresentedView: UIViewRepresentable {
 
     typealias UIView = PDFView
     @Binding var quality: Double
+    @Binding var isTextRecognition: Bool
     @ObservedObject var uploadScanDocument: NCUploadScanDocument
 
     func makeUIView(context: UIViewRepresentableContext<PDFKitRepresentedView>) -> PDFKitRepresentedView.UIViewType {
@@ -537,7 +535,7 @@ struct PDFKitRepresentedView: UIViewRepresentable {
     }
 
     func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<PDFKitRepresentedView>) {
-        let data = uploadScanDocument.createPDFPreview(quality: quality)
+        let data = uploadScanDocument.createPDFPreview(quality: quality, isTextRecognition: isTextRecognition)
         uiView.document = PDFDocument(data: data)
     }
 }

+ 101 - 0
iOSClient/Utility/FontSizeCalculator.swift

@@ -0,0 +1,101 @@
+//
+//  FontSizeCalculator.swift
+//  Nextcloud
+//
+//  Created by Marino Faggiana on 02/01/23.
+//  Copyright © 2023 Marino Faggiana. All rights reserved.
+//
+//  Author Marino Faggiana <marino.faggiana@nextcloud.com>
+//
+//  This program is free software: you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation, either version 3 of the License, or
+//  (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+import Foundation
+import UIKit
+
+//
+// Credits: https://github.com/tbaranes/FittableFontLabel/blob/master/Source/UILabelExtension.swift
+//
+
+public class FontSizeCalculator {
+
+    static var shared: FontSizeCalculator = FontSizeCalculator()
+
+    private enum FontSizeState {
+        case fit, tooBig, tooSmall
+    }
+
+    /**
+     Returns a font size of a specific string in a specific font that fits a specific size
+     - parameter text:         The text to use
+     - parameter maxFontSize:  The max font size available
+     - parameter minFontScale: The min font scale that the font will have
+     - parameter rectSize:     Rect size where the label must fit
+     - parameter fontColor:    The color of font
+     */
+    public func fontSizeThatFits(text string: String, maxFontSize: CGFloat = 100, minFontScale: CGFloat = 0.1, rectSize: CGSize) -> CGFloat {
+
+        let font = UIFont.systemFont(ofSize: 10)
+        let maxFontSize = maxFontSize.isNaN ? 100 : maxFontSize
+        let minFontScale = minFontScale.isNaN ? 0.1 : minFontScale
+        let minimumFontSize = maxFontSize * minFontScale
+        guard !string.isEmpty else {
+            return font.pointSize
+        }
+
+        let constraintSize = CGSize(width: CGFloat.greatestFiniteMagnitude, height: rectSize.height)
+        let calculatedFontSize = binarySearch(font: font, string: string, minSize: minimumFontSize, maxSize: maxFontSize, size: rectSize, constraintSize: constraintSize)
+        return (calculatedFontSize * 10.0).rounded(.down) / 10.0
+    }
+
+    private func binarySearch(font: UIFont, string: String, minSize: CGFloat, maxSize: CGFloat, size: CGSize, constraintSize: CGSize) -> CGFloat {
+
+        let fontSize = (minSize + maxSize) / 2
+        var attributes: [NSAttributedString.Key: Any] = [:]
+
+        attributes[NSAttributedString.Key.font] = font.withSize(fontSize)
+
+        let rect = string.boundingRect(with: constraintSize, options: .usesLineFragmentOrigin, attributes: attributes, context: nil)
+        let state = singleLineSizeState(rect: rect, size: size)
+
+        // if the search range is smaller than 0.1 of a font size we stop
+        // returning either side of min or max depending on the state
+        let diff = maxSize - minSize
+        guard diff > 0.1 else {
+            switch state {
+            case .tooSmall:
+                return maxSize
+            default:
+                return minSize
+            }
+        }
+
+        switch state {
+        case .fit: return fontSize
+        case .tooBig: return binarySearch(font: font, string: string, minSize: minSize, maxSize: fontSize, size: size, constraintSize: constraintSize)
+        case .tooSmall: return binarySearch(font: font, string: string, minSize: fontSize, maxSize: maxSize, size: size, constraintSize: constraintSize)
+        }
+    }
+
+    private func singleLineSizeState(rect: CGRect, size: CGSize) -> FontSizeState {
+
+        if rect.width >= size.width + 10 && rect.width <= size.width {
+            return .fit
+        } else if rect.width > size.width {
+            return .tooBig
+        } else {
+            return .tooSmall
+        }
+    }
+}