Parcourir la source

【2025】【图片转PDF】UI处理

tangchao il y a 4 mois
Parent
commit
7bf4d293c9

+ 22 - 0
PDF Office/PDF Master/Class/Appearance/Image.xcassets/Other/Empty/KMEmptyIcon.imageset/Contents.json

@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "filename" : "pic-empty.pdf",
+      "idiom" : "universal"
+    },
+    {
+      "appearances" : [
+        {
+          "appearance" : "luminosity",
+          "value" : "dark"
+        }
+      ],
+      "filename" : "pic-empty 1.pdf",
+      "idiom" : "universal"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
PDF Office/PDF Master/Class/Appearance/Image.xcassets/Other/Empty/KMEmptyIcon.imageset/pic-empty 1.pdf


BIN
PDF Office/PDF Master/Class/Appearance/Image.xcassets/Other/Empty/KMEmptyIcon.imageset/pic-empty.pdf


+ 21 - 0
PDF Office/PDF Master/Class/Appearance/Image.xcassets/PDF Tools/ImageToPDF/ImageToPDFDropdownButtonIcon.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "dropdownButton.pdf",
+      "idiom" : "universal"
+    },
+    {
+      "appearances" : [
+        {
+          "appearance" : "luminosity",
+          "value" : "dark"
+        }
+      ],
+      "idiom" : "universal"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

+ 90 - 0
PDF Office/PDF Master/Class/Appearance/Image.xcassets/PDF Tools/ImageToPDF/ImageToPDFDropdownButtonIcon.imageset/dropdownButton.pdf

@@ -0,0 +1,90 @@
+%PDF-1.7
+
+1 0 obj
+  << >>
+endobj
+
+2 0 obj
+  << /Length 3 0 R >>
+stream
+/DeviceRGB CS
+/DeviceRGB cs
+q
+1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm
+0.945098 0.945098 0.949020 scn
+0.000000 32.000000 m
+28.000000 32.000000 l
+30.209139 32.000000 32.000000 30.209139 32.000000 28.000000 c
+32.000000 4.000000 l
+32.000000 1.790861 30.209139 0.000000 28.000000 0.000000 c
+0.000000 0.000000 l
+0.000000 32.000000 l
+h
+f
+n
+Q
+q
+1.000000 0.000000 -0.000000 1.000000 10.166504 12.503937 cm
+0.509804 0.741176 1.000000 scn
+0.244078 6.585314 m
+0.569515 6.910751 1.097152 6.910751 1.422589 6.585314 c
+5.833333 2.174569 l
+10.244078 6.585314 l
+10.569514 6.910751 11.097152 6.910751 11.422588 6.585314 c
+11.748026 6.259877 11.748026 5.732239 11.422588 5.406803 c
+6.422589 0.406803 l
+6.097152 0.081366 5.569514 0.081366 5.244078 0.406803 c
+0.244078 5.406803 l
+-0.081359 5.732239 -0.081359 6.259877 0.244078 6.585314 c
+h
+f*
+n
+Q
+
+endstream
+endobj
+
+3 0 obj
+  844
+endobj
+
+4 0 obj
+  << /Annots []
+     /Type /Page
+     /MediaBox [ 0.000000 0.000000 32.000000 32.000000 ]
+     /Resources 1 0 R
+     /Contents 2 0 R
+     /Parent 5 0 R
+  >>
+endobj
+
+5 0 obj
+  << /Kids [ 4 0 R ]
+     /Count 1
+     /Type /Pages
+  >>
+endobj
+
+6 0 obj
+  << /Pages 5 0 R
+     /Type /Catalog
+  >>
+endobj
+
+xref
+0 7
+0000000000 65535 f
+0000000010 00000 n
+0000000034 00000 n
+0000000934 00000 n
+0000000956 00000 n
+0000001129 00000 n
+0000001203 00000 n
+trailer
+<< /ID [ (some) (id) ]
+   /Root 6 0 R
+   /Size 7
+>>
+startxref
+1262
+%%EOF

+ 27 - 12
PDF Office/PDF Master/Class/Batch/View/KMBatchTableCellView.swift

@@ -42,6 +42,8 @@ class KMBatchTableCellView: NSTableCellView,NSComboBoxDelegate{
     var indicateImageView: NSImageView?
     var comboBoxContent: String?
     
+    var fileIv: NSImageView?
+    
     deinit {
         DistributedNotificationCenter.default().removeObserver(self)
     }
@@ -76,8 +78,9 @@ class KMBatchTableCellView: NSTableCellView,NSComboBoxDelegate{
         self.textField?.isEditable = false
         self.addSubview(self.textField!)
         self.textField?.mas_makeConstraints({ make in
-            make?.top.equalTo()(self)?.offset()(13)
+//            make?.top.equalTo()(self)?.offset()(13)
             make?.left.equalTo()(self)
+            make?.centerY.equalTo()(self)
             
         })
         self.textField?.textColor = KMAppearance.Layout.h0Color()
@@ -126,6 +129,15 @@ class KMBatchTableCellView: NSTableCellView,NSComboBoxDelegate{
         }
     }
     func configuUIForFileName() {
+        var iv = NSImageView()
+        fileIv = iv
+        self.addSubview(iv)
+        iv.mas_makeConstraints { make in
+            make?.centerY.equalTo()(self)
+            make?.left.equalTo()(self)
+            make?.size.mas_equalTo()(NSMakeSize(40, 56))
+        }
+        
         var tf = NSTextField(frame: .zero)
         self.textField = tf
         self.textField?.isBordered = false
@@ -136,8 +148,9 @@ class KMBatchTableCellView: NSTableCellView,NSComboBoxDelegate{
         self.textField?.lineBreakMode = .byTruncatingMiddle
         self.addSubview(self.textField!)
         self.textField?.mas_makeConstraints({ make in
-            make?.top.equalTo()(self)?.offset()(13)
-            make?.left.equalTo()(self)
+//            make?.top.equalTo()(self)?.offset()(13)
+            make?.centerY.equalTo()(self)
+            make?.left.equalTo()(iv.mas_right)?.offset()(4)
             make?.right.equalTo()(self)?.offset()(-10)
         })
         self.textField?.font = NSFont.systemFont(ofSize: 12)
@@ -164,9 +177,10 @@ class KMBatchTableCellView: NSTableCellView,NSComboBoxDelegate{
         self.addSubview(self.statusView!)
         self.statusView?.mas_makeConstraints({ make in
             make?.left.equalTo()(self)
-            make?.top.equalTo()(self)?.offset()(12)
+//            make?.top.equalTo()(self)?.offset()(12)
             make?.width.equalTo()(16)
             make?.height.equalTo()(16)
+            make?.centerY.equalTo()(self)
         })
         self.indicateImageView = NSImageView(frame: .zero)
         self.statusView?.addSubview(self.indicateImageView!)
@@ -187,14 +201,14 @@ class KMBatchTableCellView: NSTableCellView,NSComboBoxDelegate{
         self.removeButton = KMButton(image: NSImage(named: KMImageNameUXIconBtnCloseNor)!, target: self, action: #selector(deleteFile(sender:)))
         self.removeButton?.isBordered = false
         self.removeButton?.isHidden = true
-        self.addSubview(self.removeButton!)
-        self.removeButton?.mas_makeConstraints({ make in
-            //            make?.left.equalTo()(self)?.offset()(10)
-            make?.centerY.equalTo()(self)
-            make?.right.equalTo()(self)?.offset()(0)
-            make?.width.equalTo()(20)
-            make?.height.equalTo()(20)
-        })
+//        self.addSubview(self.removeButton!)
+//        self.removeButton?.mas_makeConstraints({ make in
+//            //            make?.left.equalTo()(self)?.offset()(10)
+//            make?.centerY.equalTo()(self)
+//            make?.right.equalTo()(self)?.offset()(0)
+//            make?.width.equalTo()(20)
+//            make?.height.equalTo()(20)
+//        })
         self.removeButton!.mouseMoveCallback = { [weak self] mouseEntered in
             if mouseEntered {
                 self?.removeButton?.image = NSImage(named: KMImageNameUXIconBtnCloseHov)
@@ -266,6 +280,7 @@ class KMBatchTableCellView: NSTableCellView,NSComboBoxDelegate{
             } else {
                 self.errorTextField?.isHidden = true
             }
+            self.fileIv?.image = NSImage(contentsOfFile: file.filePath)
             self.textField?.stringValue = file.filePath.lastPathComponent
         } else if self.type == .PageRange {
             self.pageRangeCombobox?.isEnabled = self.file!.status != .processing

+ 1 - 1
PDF Office/PDF Master/Class/Batch/View/KMLongerButton.swift

@@ -65,7 +65,7 @@ class KMLongerButton: NSButton,KMCustomButtonPopMenuViewControllerDelegate,KMCus
     }
     override func mouseEntered(with event: NSEvent) {
         super.mouseEntered(with: event)
-        self.showPop(sender: self)
+//        self.showPop(sender: self)
         self.buttonLayer?.isHidden = false
     }
     override func mouseExited(with event: NSEvent) {

+ 362 - 33
PDF Office/PDF Master/Class/Batch/WindowController/KMBatchOperateLeftViewController.swift

@@ -10,7 +10,7 @@ import KMComponentLibrary
 
 let KMBatchDragType = "KMBatchDragType"
 
-class KMBatchOperateLeftViewController: NSViewController,NSTableViewDelegate,NSTableViewDataSource{
+class KMBatchOperateLeftViewController: KMNBaseViewController,NSTableViewDelegate,NSTableViewDataSource{
     
     @IBOutlet var selectFileButton: KMLongerButton!
     
@@ -47,9 +47,22 @@ class KMBatchOperateLeftViewController: NSViewController,NSTableViewDelegate,NST
     var popOver: NSPopover?
     var progressInt: Int = 0
     
-    private var addFileButton_: ComponentButton?
+    private var addFileButton_: ComponentDropdown?
     private var deleteButton_: ComponentButton?
     
+    private var groupView_: ComponentGroup?
+    
+    private var emptyViewTopLine: NSView = {
+        let view = NSView()
+        view.wantsLayer = true
+        return view
+    }()
+    private var emptyView_: ComponentEmpty = {
+        let view = ComponentEmpty()
+        view.properties = ComponentEmptyProperty(emptyType: .add_File, state: .normal, image: NSImage(named: "KMEmptyIcon"), text: KMLocalizedString("Select Files"), subText: KMLocalizedString("Drop files here or Click Add Files at upper left corner. You can drag files to reorder as you need."))
+        return view
+    }()
+    
     deinit {
         NotificationCenter.default.removeObserver(self)
         DistributedNotificationCenter.default().removeObserver(self)
@@ -100,51 +113,84 @@ class KMBatchOperateLeftViewController: NSViewController,NSTableViewDelegate,NST
         
 //        self.selectFileButton.containerViewController = self
         selectFileButton.title = ""
-        addFileButton_ = ComponentButton()
-        addFileButton_?.properties = ComponentButtonProperty(type: .gray, size: .s, state: .normal, showLeftIcon: true,buttonText: KMLocalizedString("Add Files"), icon: NSImage(named: "KMImageNameAddFilesIcon"))
+        addFileButton_ = ComponentDropdown()
+//        addFileButton_?.properties = ComponentButtonProperty(type: .gray, size: .s, state: .normal, showLeftIcon: true,buttonText: KMLocalizedString("Add Files"), icon: NSImage(named: "KMImageNameAddFilesIcon"))
+        addFileButton_?.properties = ComponentDropdownProperty(type: .split_graySecondary, size: .s, split: true, text: KMLocalizedString("Add Files..."))
+//        addFileButton_?.splitRightButton.properties.icon = NSImage(named: "ImageToPDFDropdownButtonIcon")
 //        addFileButton_?.setTarget(self, action: #selector(cancelButtonAction))
+        
         selectFileButton.addSubview(addFileButton_!)
         addFileButton_?.frame = selectFileButton.bounds
         addFileButton_?.autoresizingMask = [.width, .height]
+        addFileButton_?.componentDelegate = self
         
         deleteButton_ = ComponentButton()
-        deleteButton_?.properties = ComponentButtonProperty(type: .gray, size: .s, state: .normal, onlyIcon: true)
+        deleteButton_?.properties = ComponentButtonProperty(type: .text_gray_low, size: .s, state: .normal, onlyIcon: true)
         deleteButton_?.setTarget(self, action: #selector(buttonClicked_DeleteFile))
+        deleteFileButton.image = nil
         deleteFileButton.addSubview(deleteButton_!)
         deleteButton_?.frame = deleteFileButton.bounds
         deleteButton_?.autoresizingMask = [.width, .height]
         deleteButton_?.properties.propertyInfo.leftIcon_nor = NSImage(named: "KMImageNameDeleteFileIcon")
+        deleteButton_?.setTarget(self, action: #selector(buttonClicked_DeleteFile))
         
-        tableView.headerView?.wantsLayer = true
-//        tableView.headerView?.layer?.backgroundColor = NSColor.red.cgColor
-        var frame = tableView.headerView?.frame
-        frame?.size.height = 32
-        tableView.headerView?.frame = frame ?? .zero
-        
+//        tableView.headerView?.wantsLayer = true
+//        tableView.headerView?.layer?.backgroundColor = NSColor.blue.cgColor
+//        var frame = tableView.headerView?.frame
+//        frame?.size.height = 32
+//        tableView.headerView?.frame = frame ?? .zero
+        tableView.headerView = nil
         
         self.showInFinderMenuItem.title = NSLocalizedString("Show in Finder", comment: "")
         self.deleteMenuItem.title = NSLocalizedString("Delete", comment: "")
         self.blankView.wantsLayer = true
         self.blankView.layer?.backgroundColor = NSColor.clear.cgColor
-        self.blankView.titleLabel.stringValue = NSLocalizedString("Select Files", comment: "")
+        self.blankView.titleLabel.stringValue = ""
         self.blankView.imageView.isHidden = true
-        self.blankView.addButton.isHidden = false
-        self.blankView.secondTitleLabel.stringValue = NSLocalizedString("Drop files here or Click Add Files at upper left corner. You can drag files to reorder as you need.", comment: "")
+        self.blankView.addButton.isHidden = true
+        self.blankView.secondTitleLabel.stringValue = ""
         self.blankView.mouseActionCallBack = { [weak self] mouseType in
-            guard let self = self else { return }
-            if mouseType == .mouseEnter {
-                self.blankView.imageView.image = NSImage(named: "KMImageNameEmptyListHov")
-            } else if mouseType == .mouseExit {
-                self.blankView.imageView.image = NSImage(named: "KMImageNameEmptyListNor")
-            } else if mouseType == .mouseDown {
-                self.blankView.imageView.image = NSImage(named: "KMImageNameEmptyListPre")
-                self.chooseFile()
-            } else if mouseType == .mouseUp {
-                self.blankView.imageView.image = NSImage(named: "KMImageNameEmptyListHov")
-            }
+//            guard let self = self else { return }
+//            if mouseType == .mouseEnter {
+//                self.blankView.imageView.image = NSImage(named: "KMImageNameEmptyListHov")
+//            } else if mouseType == .mouseExit {
+//                self.blankView.imageView.image = NSImage(named: "KMImageNameEmptyListNor")
+//            } else if mouseType == .mouseDown {
+//                self.blankView.imageView.image = NSImage(named: "KMImageNameEmptyListPre")
+//                self.chooseFile()
+//            } else if mouseType == .mouseUp {
+//                self.blankView.imageView.image = NSImage(named: "KMImageNameEmptyListHov")
+//            }
         }
+        self.blankView.addSubview(emptyView_)
+        
+        blankView.addSubview(emptyViewTopLine)
+        emptyViewTopLine.km_add_top_constraint(constant: 4)
+        emptyViewTopLine.km_add_left_constraint(constant: 24)
+        emptyViewTopLine.km_add_right_constraint(constant: -24)
+        emptyViewTopLine.km_add_height_constraint(constant: 1)
+        emptyViewTopLine.wantsLayer = true
+        let dividerColor = ComponentLibrary.shared.getComponentColorFromKey("colorBorder/divider")
+        emptyViewTopLine.layer?.backgroundColor = dividerColor.cgColor
+        
+        emptyView_.km_add_top_constraint(constant: 96)
+        emptyView_.km_add_bottom_constraint()
+        emptyView_.km_add_leading_constraint()
+        emptyView_.km_add_trailing_constraint()
+        emptyView_.setTarget(self, action: #selector(emptyAddFileAction))
+        
         updateViewColor()
     }
+    
+    override func updateUILanguage() {
+        super.updateUILanguage()
+        
+        KMMainThreadExecute {
+            self.addFileButton_?.properties.text = KMLocalizedString("Add Files...")
+            self.addFileButton_?.reloadData()
+        }
+    }
+    
     @objc func reloadData() {
         if Thread.isMainThread {
             tableView.reloadData()
@@ -371,9 +417,9 @@ class KMBatchOperateLeftViewController: NSViewController,NSTableViewDelegate,NST
 //            if KMAlertWindowController.needShowRemoveAllFilesHint() {
                 let alert = NSAlert()
                 alert.alertStyle = .critical
-                alert.messageText = NSLocalizedString("Clear All Recents", comment: "")+"?"
-                alert.addButton(withTitle: NSLocalizedString("Delete", comment: ""))
-                alert.addButton(withTitle: NSLocalizedString("Cancel", comment: ""))
+                alert.messageText = KMLocalizedString("Clear All Recents", comment: "")+"?"
+                alert.addButton(withTitle: KMLocalizedString("Delete", comment: ""))
+                alert.addButton(withTitle: KMLocalizedString("Cancel", comment: ""))
                 alert.beginSheetModal(for: self.view.window!) {[weak self] response in
                     if response == NSApplication.ModalResponse.alertFirstButtonReturn {
                         self?.files.removeAll()
@@ -501,23 +547,176 @@ class KMBatchOperateLeftViewController: NSViewController,NSTableViewDelegate,NST
         }
         addFilesToList(addArray: pdfArray)
     }
+    
+    // MARK: - Actions
+    
+    @objc func emptyAddFileAction() {
+        self.chooseFile()
+    }
+    
+    //MARK: - GroupView
+    
+    func showGroupView() {
+        var viewHeight: CGFloat = 8
+        var menuItemArr: [ComponentMenuitemProperty] = []
+        for i in ["Add Files...", "Add Folder...", "Import from Clipboard...", "Import from Scanner..."] {
+            let properties_Menuitem: ComponentMenuitemProperty = ComponentMenuitemProperty(multipleSelect: false,
+                                                                                               itemSelected: false,
+                                                                                               isDisabled: false,
+                                                                                               keyEquivalent: nil,
+                                                                                               text: KMLocalizedString(i))
+            menuItemArr.append(properties_Menuitem)
+            viewHeight += 36
+        }
+        
+        if groupView_ == nil {
+            groupView_ = ComponentGroup.createFromNib(in: ComponentLibrary.shared.componentBundle())
+        }
+        groupView_?.groupDelegate = self
+        groupView_?.frame = CGRectMake(310, 0, 200, viewHeight)
+        groupView_?.updateGroupInfo(menuItemArr)
+        
+        var point = addFileButton_?.convert(addFileButton_!.frame.origin, to: nil) ?? .zero
+        point.y -= viewHeight
+        groupView_?.showWithPoint(point, relativeTo: addFileButton_)
+        
+        addFileButton_?.properties.state = .pressed
+        addFileButton_?.reloadData()
+    }
+    
+    func removeGroupView() {
+        if groupView_ != nil {
+            groupView_?.removeFromSuperview()
+        }
+        addFileButton_?.properties.state = .normal
+        addFileButton_?.reloadData()
+    }
+    
+    func openDocumentWithImageFromPasteboard(_ pboard: NSPasteboard, error outError: AutoreleasingUnsafeMutablePointer<NSError?>?) -> CPDFDocument? {
+        var document: CPDFDocument? = nil
+        var data: Data? = nil
+        
+        if pboard.canReadItem(withDataConformingToTypes: [NSPasteboard.PasteboardType.pdf.rawValue]) {
+            data = pboard.data(forType: NSPasteboard.PasteboardType.pdf)
+        } else if pboard.canReadItem(withDataConformingToTypes: [NSPasteboard.PasteboardType.postScript.rawValue]) {
+            data = pboard.data(forType: NSPasteboard.PasteboardType.postScript)
+        } else if pboard.canReadItem(withDataConformingToTypes: [NSPasteboard.PasteboardType.tiff.rawValue]) {
+            data = convertTIFFDataToPDF(pboard.data(forType: NSPasteboard.PasteboardType.tiff) ?? Data())
+        } else {
+            let images = pboard.readObjects(forClasses: [NSImage.self], options: [:])
+            let strings = pboard.readObjects(forClasses: [NSAttributedString.self], options: [:])
+            if images?.count ?? 0 > 0 {
+                data = convertTIFFDataToPDF((images![0] as AnyObject).tiffRepresentation!)
+            } else if strings?.count ?? 0 > 0 {
+                data = KMOCTool.convertStringsToPDF(withString: strings ?? [""]) // convertStringsToPDF(strings!)
+            }
+        }
+        
+        if let data = data {
+            document = CPDFDocument(data: data)
+            
+        } else if let outError = outError {
+            outError.pointee = NSError(domain: "SKDocumentErrorDomain", code: 3, userInfo: [NSLocalizedDescriptionKey: NSLocalizedString("Unable to load data from clipboard", comment: "Error description")])
+        }
+    
+        return document
+    }
+    
+    func convertTIFFDataToPDF(_ tiffData: Data) -> Data? {
+        guard let imsrc = CGImageSourceCreateWithData(tiffData as CFData, [kCGImageSourceTypeIdentifierHint: kUTTypeTIFF] as CFDictionary), CGImageSourceGetCount(imsrc) > 0, let cgImage = CGImageSourceCreateImageAtIndex(imsrc, 0, nil) else { return nil }
+        let pdfData = NSMutableData(capacity: tiffData.count)
+        let consumer = CGDataConsumer(data: pdfData! as CFMutableData)!
+        
+        var rect = CGRect(x: 0, y: 0, width: CGFloat(cgImage.width), height: CGFloat(cgImage.height))
+        let ctxt = CGContext(consumer: consumer, mediaBox: &rect, nil)
+        ctxt!.beginPDFPage(nil)
+        ctxt!.draw(cgImage, in: rect)
+        ctxt!.endPDFPage()
+        ctxt!.closePDF()
+        
+        return pdfData as? Data
+    }
+    
+    // MARK: - Private Methods
+    
+    private func _saveImagePath() -> String {
+        let rootPath = KMDataManager.fetchAppSupportOfBundleIdentifierDirectory()
+        let path = rootPath.appendingPathComponent("ImageToPDF").path
+        if FileManager.default.fileExists(atPath: path) == false {
+            try?FileManager.default.createDirectory(atPath: path, withIntermediateDirectories: false)
+        }
+        return path
+    }
+    
+    private func _clearImageData() {
+        let path = self._saveImagePath()
+        if FileManager.default.fileExists(atPath: path) {
+            try?FileManager.default.removeItem(atPath: path)
+        }
+    }
+    
+    
     func numberOfRows(in tableView: NSTableView) -> Int {
         NotificationCenter.default.post(name: NSNotification.Name(rawValue: "KMBatchFilesCountNotification"), object: self.files, userInfo: [kObjectKey : self])
         self.deleteFileButton.isEnabled = self.files.count > 0
+        deleteButton_?.properties.isDisabled = self.files.count <= 0
         self.blankView.isHidden = self.files.count > 0
-        return self.files.count;
+        if self.files.count == 0 {
+            return 0
+        }
+        return self.files.count + 1;
     }
     func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
         let identifier = tableColumn?.identifier
-        let file = self.files[row]
+        
+        let rowIdx = max(0, row-1)
+        let file = self.files[rowIdx]
+        
+        let cellColor = ComponentLibrary.shared.getComponentColorFromKey("olorFill/4")
+        let dividerColor = ComponentLibrary.shared.getComponentColorFromKey("colorBorder/divider")
+        let titleFont = ComponentLibrary.shared.getFontFromKey("mac/body-s-medium")
+        let titleColor = ComponentLibrary.shared.getComponentColorFromKey("colorText/1")
       
         if identifier?.rawValue == "index" {
+            if row == 0 {
+                let cellView = KMNTableHeaderCellView()
+                cellView.wantsLayer = true
+                cellView.layer?.backgroundColor = cellColor.cgColor
+//                cellView.layer?.backgroundColor = NSColor(hex: "#F6F6F8").cgColor
+
+                cellView.titleLabel.stringValue = KMLocalizedString("")
+                
+                cellView.leftLine.wantsLayer = true
+                cellView.leftLine.layer?.backgroundColor = dividerColor.cgColor
+                cellView.rightLine.wantsLayer = true
+                cellView.rightLine.layer?.backgroundColor = dividerColor.cgColor
+                cellView.bottomLine.wantsLayer = true
+                cellView.bottomLine.layer?.backgroundColor = dividerColor.cgColor
+                return cellView
+            }
             let cellView = KMBatchTableCellView(type: .Size)
             _ = row + 1
             cellView.textField?.stringValue = String(format: "%d", row + 1);
             return cellView;
         } else if identifier?.rawValue == "pageRange"{
             if (file.currentOperateType == .CreatePDF) {
+                if row == 0 {
+                    let cellView = KMNTableHeaderCellView()
+                    cellView.wantsLayer = true
+                    cellView.layer?.backgroundColor = cellColor.cgColor
+                    
+                    cellView.titleLabel.stringValue = KMLocalizedString("Dimensions")
+                    cellView.titleLabel.font = titleFont
+                    cellView.titleLabel.textColor = titleColor
+
+                    cellView.leftLine.wantsLayer = true
+                    cellView.leftLine.layer?.backgroundColor = dividerColor.cgColor
+                    cellView.rightLine.wantsLayer = true
+                    cellView.rightLine.layer?.backgroundColor = dividerColor.cgColor
+                    cellView.bottomLine.wantsLayer = true
+                    cellView.bottomLine.layer?.backgroundColor = dividerColor.cgColor
+                    return cellView
+                }
                 let cellView = KMBatchTableCellView(type: .Size)
                 
                 if (file.fileType == .Image) {
@@ -532,6 +731,23 @@ class KMBatchOperateLeftViewController: NSViewController,NSTableViewDelegate,NST
                 return cellView;
             }
         } else if identifier?.rawValue == "status"{
+            if row == 0 {
+                let cellView = KMNTableHeaderCellView()
+                cellView.wantsLayer = true
+                cellView.layer?.backgroundColor = cellColor.cgColor
+
+                cellView.titleLabel.stringValue = KMLocalizedString("State")
+                cellView.titleLabel.font = titleFont
+                cellView.titleLabel.textColor = titleColor
+                
+                cellView.leftLine.wantsLayer = true
+                cellView.leftLine.layer?.backgroundColor = dividerColor.cgColor
+                cellView.rightLine.wantsLayer = true
+                cellView.rightLine.layer?.backgroundColor = dividerColor.cgColor
+                cellView.bottomLine.wantsLayer = true
+                cellView.bottomLine.layer?.backgroundColor = dividerColor.cgColor
+                return cellView
+            }
             let cellView = KMBatchTableCellView(type: .Status)
             if (file.currentOperateType == .CreatePDF) {
                 cellView.updateInterface(file: file, progress: file.progress ?? 0)
@@ -544,12 +760,51 @@ class KMBatchOperateLeftViewController: NSViewController,NSTableViewDelegate,NST
             }
             return cellView;
         } else if identifier?.rawValue == "size"{
+            if row == 0 {
+                let cellView = KMNTableHeaderCellView()
+                cellView.wantsLayer = true
+                cellView.layer?.backgroundColor = cellColor.cgColor
+                
+                cellView.titleLabel.stringValue = KMLocalizedString("Size")
+                cellView.titleLabel.font = titleFont
+                cellView.titleLabel.textColor = titleColor
+
+                cellView.leftLine.wantsLayer = true
+                cellView.leftLine.layer?.backgroundColor = dividerColor.cgColor
+                cellView.rightLine.wantsLayer = true
+                cellView.rightLine.layer?.backgroundColor = dividerColor.cgColor
+                cellView.bottomLine.wantsLayer = true
+                cellView.bottomLine.layer?.backgroundColor = dividerColor.cgColor
+                return cellView
+            }
             let cellView = KMBatchTableCellView(type: .Size)
             cellView.updateInterface(file)
             return cellView;
         } else if identifier?.rawValue == "fileName"{
+            if row == 0 {
+                let cellView = KMNTableHeaderCellView()
+                cellView.wantsLayer = true
+                cellView.layer?.backgroundColor = cellColor.cgColor
+                
+                cellView.titleLabel.stringValue = KMLocalizedString("File Name")
+                cellView.titleLabel.font = titleFont
+                cellView.titleLabel.textColor = titleColor
+
+                cellView.leftLine.wantsLayer = true
+                cellView.leftLine.layer?.backgroundColor = dividerColor.cgColor
+                cellView.rightLine.wantsLayer = true
+                cellView.rightLine.layer?.backgroundColor = dividerColor.cgColor
+                cellView.bottomLine.wantsLayer = true
+                cellView.bottomLine.layer?.backgroundColor = dividerColor.cgColor
+                return cellView
+            }
             let cellView = KMBatchTableCellView(type: .FileName)
             cellView.updateInterface(file)
+            
+            cellView.fileIv?.wantsLayer = true
+            cellView.fileIv?.layer?.borderWidth = 1
+            cellView.fileIv?.layer?.borderColor = ComponentLibrary.shared.getComponentColorFromKey("colorBorder/3-default").cgColor
+            
             let rowView: KMBatchTableRowView = tableView.rowView(atRow: row, makeIfNecessary: true) as! KMBatchTableRowView
             if ((file.error) != nil) {
                 rowView.backgroundColor = KMAppearance.Status.errBGColor();
@@ -560,6 +815,24 @@ class KMBatchOperateLeftViewController: NSViewController,NSTableViewDelegate,NST
             cellView.updateInterface(file)
             return cellView;
         } else if identifier?.rawValue == "dimensions"{
+            if row == 0 {
+                let cellView = KMNTableHeaderCellView()
+                cellView.wantsLayer = true
+                cellView.layer?.backgroundColor = cellColor.cgColor
+                
+                cellView.titleLabel.stringValue = KMLocalizedString("Dimensions")
+                cellView.titleLabel.font = titleFont
+                cellView.titleLabel.textColor = titleColor
+
+                cellView.leftLine.wantsLayer = true
+                cellView.leftLine.layer?.backgroundColor = dividerColor.cgColor
+                cellView.rightLine.wantsLayer = true
+                cellView.rightLine.layer?.backgroundColor = dividerColor.cgColor
+                cellView.bottomLine.wantsLayer = true
+                cellView.bottomLine.layer?.backgroundColor = dividerColor.cgColor
+//                cellView.
+                return cellView
+            }
             let cellView = KMBatchTableCellView(type: .Size)
             
             if (file.fileType == .Image) {
@@ -572,12 +845,16 @@ class KMBatchOperateLeftViewController: NSViewController,NSTableViewDelegate,NST
         return nil;
     }
     func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat {
-        let file = self.files[row]
+        let rowIdx = max(0, row-1)
+        let file = self.files[rowIdx]
         if self.type == .CreatePDF {
+            if row == 0 {
+                return 32
+            }
             if (file.error != nil) {
-                return 64
+                return 104
             } else {
-                return 40
+                return 80
             }
         } else {
             if file.fileType == .PDF {
@@ -592,6 +869,15 @@ class KMBatchOperateLeftViewController: NSViewController,NSTableViewDelegate,NST
         }
     }
     func tableView(_ tableView: NSTableView, rowViewForRow row: Int) -> NSTableRowView? {
+        if row == 0 {
+            let rowView = KMBatchTableRowView()
+            rowView.selectionBackgroundColorBlock = {
+                return .clear
+            }
+            rowView.selectionHighlightStyle = .none
+            rowView.isSelected = false
+            return rowView
+        }
         let rowView = KMBatchTableRowView()
         return rowView
     }
@@ -832,3 +1118,46 @@ extension KMBatchOperateLeftViewController: NSMenuDelegate, NSMenuItemValidation
         return true
     }
 }
+
+//MARK: - ComponentDropdownDelegate
+
+extension KMBatchOperateLeftViewController: ComponentDropdownDelegate {
+    func componentDropdownDidShowMenuItem(dropdown: ComponentDropdown) {
+        showGroupView()
+    }
+}
+
+//MARK: - ComponentGroupDelegate
+
+extension KMBatchOperateLeftViewController: ComponentGroupDelegate {
+    func componentGroupDidDismiss(group: ComponentGroup?) {
+        
+        removeGroupView()
+    }
+    
+    func componentGroupDidSelect(group: ComponentGroup?, menuItemProperty: ComponentMenuitemProperty?) {
+        if let selItem = menuItemProperty {
+            let index = group?.menuItemArr.firstIndex(of: selItem)
+            if index == 0 {
+                chooseFile()
+            } else if index == 1 {
+                chooseFile()
+            } else if index == 2 {
+                let pboard = NSPasteboard.general
+                if let document = self.openDocumentWithImageFromPasteboard(pboard, error: nil) {
+                    // Document opened successfully
+                    if let page = document.page(at: 0) {
+                        let data = page.PDFListViewTIFFData(for: page.bounds)
+                        var path = self._saveImagePath() + "/Untitled.png"
+                        path = KMTools.getUniqueFilePath(filePath: path)
+                        try?data?.write(to: URL(fileURLWithPath: path), options: .atomic)
+                        
+                        self.addFilesToList(addArray: [path])
+                    }
+                }
+            } else if index == 3 {
+                chooseFileFromCamera()
+            }
+        }
+    }
+}

+ 24 - 25
PDF Office/PDF Master/Class/Batch/WindowController/KMBatchOperateLeftViewController.xib

@@ -28,11 +28,11 @@
         <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
         <customObject id="-3" userLabel="Application" customClass="NSObject"/>
         <customView misplaced="YES" id="Hz6-mo-xeY">
-            <rect key="frame" x="0.0" y="0.0" width="698" height="464"/>
+            <rect key="frame" x="0.0" y="0.0" width="616" height="560"/>
             <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
             <subviews>
                 <customView translatesAutoresizingMaskIntoConstraints="NO" id="yD5-qe-EWK">
-                    <rect key="frame" x="0.0" y="400" width="718" height="64"/>
+                    <rect key="frame" x="0.0" y="421" width="718" height="64"/>
                     <subviews>
                         <button verticalHuggingPriority="750" imageHugsTitle="YES" translatesAutoresizingMaskIntoConstraints="NO" id="9ff-Qn-trv" customClass="KMLongerButton" customModule="PDF_Reader_Pro" customModuleProvider="target">
                             <rect key="frame" x="24" y="12" width="109" height="32"/>
@@ -68,20 +68,19 @@
                         <constraint firstItem="9ff-Qn-trv" firstAttribute="leading" secondItem="yD5-qe-EWK" secondAttribute="leading" constant="24" id="ol8-K1-cmb"/>
                     </constraints>
                 </customView>
-                <scrollView autohidesScrollers="YES" horizontalLineScroll="19" horizontalPageScroll="10" verticalLineScroll="19" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="cSo-1J-C87">
-                    <rect key="frame" x="24" y="0.0" width="670" height="400"/>
+                <scrollView autohidesScrollers="YES" horizontalLineScroll="17" horizontalPageScroll="10" verticalLineScroll="17" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="cSo-1J-C87">
+                    <rect key="frame" x="24" y="0.0" width="670" height="421"/>
                     <clipView key="contentView" ambiguous="YES" id="5QZ-3D-5sN">
-                        <rect key="frame" x="1" y="1" width="668" height="398"/>
+                        <rect key="frame" x="1" y="1" width="668" height="419"/>
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <subviews>
-                            <tableView verticalHuggingPriority="750" ambiguous="YES" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnSelection="YES" multipleSelection="NO" autosaveColumns="NO" rowSizeStyle="automatic" headerView="Mlr-rw-6rm" viewBased="YES" id="iqp-fI-b2v">
-                                <rect key="frame" x="0.0" y="0.0" width="740" height="373"/>
+                            <tableView verticalHuggingPriority="750" ambiguous="YES" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" tableStyle="fullWidth" columnSelection="YES" multipleSelection="NO" autosaveColumns="NO" rowSizeStyle="automatic" headerView="Mlr-rw-6rm" viewBased="YES" id="iqp-fI-b2v">
+                                <rect key="frame" x="0.0" y="0.0" width="859" height="394"/>
                                 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
-                                <size key="intercellSpacing" width="3" height="2"/>
                                 <color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
                                 <color key="gridColor" red="1" green="0.64784158279075421" blue="0.26014074763814632" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                 <tableColumns>
-                                    <tableColumn identifier="index" width="72" minWidth="72" maxWidth="72" id="dvO-PE-2DL">
+                                    <tableColumn identifier="index" width="40" minWidth="40" maxWidth="40" id="dvO-PE-2DL">
                                         <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="序号">
                                             <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
                                             <color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
@@ -94,12 +93,12 @@
                                         <tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
                                         <prototypeCellViews>
                                             <tableCellView id="mJ1-Fh-j8e">
-                                                <rect key="frame" x="1" y="1" width="77" height="17"/>
+                                                <rect key="frame" x="0.0" y="0.0" width="45" height="17"/>
                                                 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                                             </tableCellView>
                                         </prototypeCellViews>
                                     </tableColumn>
-                                    <tableColumn identifier="fileName" width="100" minWidth="100" maxWidth="1000" id="TTZ-qf-vYt">
+                                    <tableColumn identifier="fileName" width="219" minWidth="219" maxWidth="1000" id="TTZ-qf-vYt">
                                         <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="文件名">
                                             <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
                                             <color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
@@ -112,7 +111,7 @@
                                         <tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
                                         <prototypeCellViews>
                                             <tableCellView id="Mgh-hp-ErW">
-                                                <rect key="frame" x="81" y="1" width="100" height="17"/>
+                                                <rect key="frame" x="46" y="0.0" width="219" height="17"/>
                                                 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                                             </tableCellView>
                                         </prototypeCellViews>
@@ -129,12 +128,12 @@
                                         </textFieldCell>
                                         <prototypeCellViews>
                                             <tableCellView id="nlT-SK-XE6" customClass="KMBatchTableCellView" customModule="PDF_Reader_Pro" customModuleProvider="target">
-                                                <rect key="frame" x="184" y="1" width="140" height="17"/>
+                                                <rect key="frame" x="265" y="0.0" width="140" height="17"/>
                                                 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                                             </tableCellView>
                                         </prototypeCellViews>
                                     </tableColumn>
-                                    <tableColumn identifier="size" width="80" minWidth="80" maxWidth="80" id="Jv9-CS-hrB">
+                                    <tableColumn identifier="size" width="88" minWidth="88" maxWidth="88" id="Jv9-CS-hrB">
                                         <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="大小">
                                             <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
                                             <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
@@ -147,12 +146,12 @@
                                         <tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
                                         <prototypeCellViews>
                                             <tableCellView id="TSm-ys-xdB">
-                                                <rect key="frame" x="327" y="1" width="80" height="17"/>
+                                                <rect key="frame" x="405" y="0.0" width="88" height="17"/>
                                                 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                                             </tableCellView>
                                         </prototypeCellViews>
                                     </tableColumn>
-                                    <tableColumn identifier="status" width="78" minWidth="78" maxWidth="78" id="vhM-02-bDl">
+                                    <tableColumn identifier="status" width="56" minWidth="56" maxWidth="56" id="vhM-02-bDl">
                                         <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="状态">
                                             <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
                                             <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
@@ -165,11 +164,11 @@
                                         <tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
                                         <prototypeCellViews>
                                             <tableCellView id="sVm-ab-mJ4">
-                                                <rect key="frame" x="410" y="1" width="78" height="17"/>
+                                                <rect key="frame" x="493" y="0.0" width="56" height="17"/>
                                                 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                                                 <subviews>
                                                     <customView translatesAutoresizingMaskIntoConstraints="NO" id="QVD-OT-qtp">
-                                                        <rect key="frame" x="0.0" y="0.0" width="78" height="17"/>
+                                                        <rect key="frame" x="0.0" y="0.0" width="56" height="17"/>
                                                     </customView>
                                                 </subviews>
                                                 <constraints>
@@ -194,12 +193,12 @@
                                         <tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
                                         <prototypeCellViews>
                                             <tableCellView id="tdZ-lu-oAc" customClass="KMBatchTableCellView" customModule="PDF_Reader_Pro" customModuleProvider="target">
-                                                <rect key="frame" x="491" y="1" width="140" height="17"/>
+                                                <rect key="frame" x="549" y="0.0" width="140" height="17"/>
                                                 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                                             </tableCellView>
                                         </prototypeCellViews>
                                     </tableColumn>
-                                    <tableColumn identifier="dimensions" width="100" minWidth="100" maxWidth="100" id="BoK-gf-WJ0">
+                                    <tableColumn identifier="dimensions" width="164" minWidth="164" maxWidth="164" id="BoK-gf-WJ0">
                                         <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="center" title="Dimensions">
                                             <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
                                             <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
@@ -212,7 +211,7 @@
                                         <tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
                                         <prototypeCellViews>
                                             <tableCellView id="nvT-ce-HBH" customClass="KMBatchTableCellView" customModule="PDF_Reader_Pro" customModuleProvider="target">
-                                                <rect key="frame" x="634" y="1" width="104" height="17"/>
+                                                <rect key="frame" x="689" y="0.0" width="168" height="17"/>
                                                 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                                             </tableCellView>
                                         </prototypeCellViews>
@@ -231,7 +230,7 @@
                         <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="670" id="LUW-2r-W1h"/>
                     </constraints>
                     <scroller key="horizontalScroller" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="RBU-7C-fCt">
-                        <rect key="frame" x="1" y="383" width="668" height="16"/>
+                        <rect key="frame" x="1" y="404" width="668" height="16"/>
                         <autoresizingMask key="autoresizingMask"/>
                     </scroller>
                     <scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="32b-Um-caF">
@@ -239,15 +238,15 @@
                         <autoresizingMask key="autoresizingMask"/>
                     </scroller>
                     <tableHeaderView key="headerView" wantsLayer="YES" id="Mlr-rw-6rm" customClass="KMTableHeaderView" customModule="PDF_Reader_Pro" customModuleProvider="target">
-                        <rect key="frame" x="0.0" y="0.0" width="740" height="25"/>
+                        <rect key="frame" x="0.0" y="0.0" width="859" height="25"/>
                         <autoresizingMask key="autoresizingMask"/>
                     </tableHeaderView>
                 </scrollView>
                 <customView translatesAutoresizingMaskIntoConstraints="NO" id="G6v-if-4fr" customClass="KMBlankView" customModule="PDF_Reader_Pro" customModuleProvider="target">
-                    <rect key="frame" x="0.0" y="0.0" width="718" height="400"/>
+                    <rect key="frame" x="0.0" y="0.0" width="718" height="421"/>
                     <subviews>
                         <customView translatesAutoresizingMaskIntoConstraints="NO" id="9GJ-Lf-bRA">
-                            <rect key="frame" x="222" y="105" width="275" height="190"/>
+                            <rect key="frame" x="222" y="116" width="275" height="190"/>
                             <subviews>
                                 <imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="aT2-4b-2xG">
                                     <rect key="frame" x="67" y="50" width="140" height="140"/>

+ 112 - 0
PDF Office/PDF Master/KMClass/ImageToPDF/View/KMNTableHeaderCellView.swift

@@ -0,0 +1,112 @@
+//
+//  KMNTableHeaderCellView.swift
+//  PDF Reader Pro
+//
+//  Created by User-Tangchao on 2024/11/7.
+//
+
+import Cocoa
+
+class KMNTableHeaderCellView: NSTableCellView {
+    private var contentBox: NSBox = {
+        let box = NSBox()
+        box.boxType = .custom
+        box.titlePosition = .noTitle
+        box.contentViewMargins = .zero
+        box.borderWidth = 0
+        return box
+    }()
+    
+    private var titleLabel_: NSTextField = {
+        let view = NSTextField(labelWithString: "")
+        return view
+    }()
+    
+    private var leftVLine_: NSView = {
+        let view = NSView()
+        return view
+    }()
+    
+    private var rightVLine_: NSView = {
+        let view = NSView()
+        return view
+    }()
+    
+    private var bottomLine_: NSView = {
+        let view = NSView()
+        return view
+    }()
+    
+    var titleLabel: NSTextField {
+        get {
+            return self.titleLabel_
+        }
+    }
+    
+    var leftLine: NSView {
+        get {
+            return self.leftVLine_
+        }
+    }
+    
+    var rightLine: NSView {
+        get {
+            return self.rightVLine_
+        }
+    }
+    
+    var bottomLine: NSView {
+        get {
+            return self.bottomLine_
+        }
+    }
+
+    override func draw(_ dirtyRect: NSRect) {
+        super.draw(dirtyRect)
+
+        // Drawing code here.
+    }
+    
+    convenience init() {
+        self.init(frame: .init(x: 0, y: 0, width: 40, height: 40))
+        
+        initSubviews()
+    }
+    
+    override func awakeFromNib() {
+        super.awakeFromNib()
+        
+        initSubviews()
+    }
+    
+    func initSubviews() {
+        addSubview(contentBox)
+        contentBox.km_add_inset_constraint()
+        
+        contentBox.contentView?.addSubview(leftVLine_)
+        contentBox.contentView?.addSubview(titleLabel_)
+        contentBox.contentView?.addSubview(rightVLine_)
+        contentBox.contentView?.addSubview(bottomLine_)
+        
+        leftVLine_.km_add_leading_constraint()
+        leftVLine_.km_add_top_constraint(constant: 4)
+        leftVLine_.km_add_bottom_constraint(constant: -4)
+        leftVLine_.km_add_width_constraint(constant: 0.5)
+        
+        titleLabel_.km_add_leading_constraint(constant: 8)
+        titleLabel_.km_add_centerY_constraint()
+        
+        rightVLine_.km_add_trailing_constraint()
+        rightVLine_.km_add_top_constraint(constant: 4)
+        rightVLine_.km_add_bottom_constraint(constant: -4)
+        rightVLine_.km_add_width_constraint(constant: 0.5)
+        
+        bottomLine_.km_add_bottom_constraint(constant: 0)
+        bottomLine_.km_add_leading_constraint(constant: 0)
+        bottomLine_.km_add_trailing_constraint(constant: 0)
+        bottomLine_.km_add_height_constraint(constant: 1)
+        
+        contentBox.fillColor = .clear
+    }
+    
+}

+ 40 - 0
PDF Office/PDF Reader Pro.xcodeproj/project.pbxproj

@@ -53,6 +53,9 @@
 		65341C7C2C646C6400FE30F9 /* KMSearchReplaceHanddler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65341C7B2C646C6400FE30F9 /* KMSearchReplaceHanddler.swift */; };
 		65341C7D2C646C6400FE30F9 /* KMSearchReplaceHanddler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65341C7B2C646C6400FE30F9 /* KMSearchReplaceHanddler.swift */; };
 		65341C7E2C646C6400FE30F9 /* KMSearchReplaceHanddler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65341C7B2C646C6400FE30F9 /* KMSearchReplaceHanddler.swift */; };
+		653647702CDC8C3700CDB13E /* KMNTableHeaderCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6536476F2CDC8C3700CDB13E /* KMNTableHeaderCellView.swift */; };
+		653647712CDC8C3700CDB13E /* KMNTableHeaderCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6536476F2CDC8C3700CDB13E /* KMNTableHeaderCellView.swift */; };
+		653647722CDC8C3700CDB13E /* KMNTableHeaderCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6536476F2CDC8C3700CDB13E /* KMNTableHeaderCellView.swift */; };
 		6536FDE32C9C1EF2004A0FB9 /* KMNoteReplyHanddler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6536FDE22C9C1EF2004A0FB9 /* KMNoteReplyHanddler.swift */; };
 		6536FDE42C9C1EF2004A0FB9 /* KMNoteReplyHanddler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6536FDE22C9C1EF2004A0FB9 /* KMNoteReplyHanddler.swift */; };
 		6536FDE52C9C1EF2004A0FB9 /* KMNoteReplyHanddler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6536FDE22C9C1EF2004A0FB9 /* KMNoteReplyHanddler.swift */; };
@@ -5979,6 +5982,7 @@
 		65341C722C63CCFE00FE30F9 /* KMSearchReplaceWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KMSearchReplaceWindowController.swift; sourceTree = "<group>"; };
 		65341C732C63CCFE00FE30F9 /* KMSearchReplaceWindowController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = KMSearchReplaceWindowController.xib; sourceTree = "<group>"; };
 		65341C7B2C646C6400FE30F9 /* KMSearchReplaceHanddler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KMSearchReplaceHanddler.swift; sourceTree = "<group>"; };
+		6536476F2CDC8C3700CDB13E /* KMNTableHeaderCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KMNTableHeaderCellView.swift; sourceTree = "<group>"; };
 		6536FDE22C9C1EF2004A0FB9 /* KMNoteReplyHanddler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KMNoteReplyHanddler.swift; sourceTree = "<group>"; };
 		6536FDE62C9C49A6004A0FB9 /* KMNoteFooterCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KMNoteFooterCellView.swift; sourceTree = "<group>"; };
 		6536FDEA2C9C49C0004A0FB9 /* KMNoteFooterCellView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = KMNoteFooterCellView.xib; sourceTree = "<group>"; };
@@ -8536,6 +8540,38 @@
 			path = Tools;
 			sourceTree = "<group>";
 		};
+		6536476A2CDC8B0900CDB13E /* ImageToPDF */ = {
+			isa = PBXGroup;
+			children = (
+				6536476C2CDC8B3400CDB13E /* Controller */,
+				6536476D2CDC8B3400CDB13E /* View */,
+				6536476E2CDC8B3400CDB13E /* Window */,
+			);
+			path = ImageToPDF;
+			sourceTree = "<group>";
+		};
+		6536476C2CDC8B3400CDB13E /* Controller */ = {
+			isa = PBXGroup;
+			children = (
+			);
+			path = Controller;
+			sourceTree = "<group>";
+		};
+		6536476D2CDC8B3400CDB13E /* View */ = {
+			isa = PBXGroup;
+			children = (
+				6536476F2CDC8C3700CDB13E /* KMNTableHeaderCellView.swift */,
+			);
+			path = View;
+			sourceTree = "<group>";
+		};
+		6536476E2CDC8B3400CDB13E /* Window */ = {
+			isa = PBXGroup;
+			children = (
+			);
+			path = Window;
+			sourceTree = "<group>";
+		};
 		655445062C88481300BD9010 /* DiscountToSave */ = {
 			isa = PBXGroup;
 			children = (
@@ -13163,6 +13199,7 @@
 		BB5A9D252CB651C900F64C1F /* KMClass */ = {
 			isa = PBXGroup;
 			children = (
+				6536476A2CDC8B0900CDB13E /* ImageToPDF */,
 				F3EF17812CD5FC230007D364 /* Left */,
 				651559072CCA6D0400C0F0D9 /* Convert */,
 				F39603E42CC62E55003C6F71 /* KMNPDFPageEdit */,
@@ -18214,6 +18251,7 @@
 				BB234F072BA3D798008B3754 /* KMAIIconGuideView.swift in Sources */,
 				BBD1F798296FF78C00343885 /* KMPageEditSettingBaseModel.swift in Sources */,
 				BB4F7E892B0C55E70077EC8C /* KMFilterAuthorLabel.swift in Sources */,
+				653647702CDC8C3700CDB13E /* KMNTableHeaderCellView.swift in Sources */,
 				9FAAA33E290FECA70046FFCE /* NSImage+QuickLook.swift in Sources */,
 				ADE3C1E429A5ABC200793B13 /* KMLoginWindowController.swift in Sources */,
 				AD85D1B92AF0D2CA000F4D28 /* KMHomeQuickToolsCollectionView.swift in Sources */,
@@ -19615,6 +19653,7 @@
 				AD867FB029DFBB1200F00440 /* KMAnnotationOutlineCellView.swift in Sources */,
 				BB5A9D5C2CB6521400F64C1F /* SettingsManager.swift in Sources */,
 				BBFEF7182B3A77E700C28AC0 /* KMSystemFileMenu.swift in Sources */,
+				653647712CDC8C3700CDB13E /* KMNTableHeaderCellView.swift in Sources */,
 				AD867F9529D955BF00F00440 /* KMBOTAOutlineCellView.swift in Sources */,
 				AD58F40F2B1DAAA800299EE0 /* KMPrintDefaultView.swift in Sources */,
 				BB03D68D2B01C782008C9976 /* KMPDFEditInsertBlankPageWindow.swift in Sources */,
@@ -20316,6 +20355,7 @@
 				BB4BD9CE2909026500A66A65 /* KMRightSideViewController.swift in Sources */,
 				BBF7299D2B1961E800576AC5 /* KMAddWatermarkOprationQueue.swift in Sources */,
 				9F0CB50B2986563300007028 /* KMDesignToken+BorderBottom.swift in Sources */,
+				653647722CDC8C3700CDB13E /* KMNTableHeaderCellView.swift in Sources */,
 				BBEC00E3295C410A00A26C98 /* KMBatesPrefixInfoView.swift in Sources */,
 				9FCFEC9E2AD152FA00EAD2CB /* CustomAlertView.swift in Sources */,
 				BB147007299DC0D100784A6A /* OIDFieldMapping.m in Sources */,