79550609

Date: 2025-04-02 12:25:00
Score: 2.5
Natty:
Report link
from io import BytesIO
import twain
import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import logging
import PIL.ImageTk
import PIL.Image
import datetime

scanned_image = None
current_settings = {
    'scan_mode': 'Color',
    'resolution': 300,
    'document_size': 'A4',
    'document_type': 'Normal',
    'auto_crop': False,
    'brightness': 0,
    'contrast': 0,
    'destination': 'File',
    'file_format': 'JPEG',
    'file_path': ''
}

def check_adf_support(src):
    """Check if the scanner supports ADF and return ADF status"""
    try:
        # Check if ADF is supported
        if src.get_capability(twain.CAP_FEEDERENABLED):
            print("ADF is supported by this scanner")
            
            # Check if ADF is loaded with documents
            if src.get_capability(twain.CAP_FEEDERLOADED):
                print("ADF has documents loaded")
                return True
            else:
                print("ADF is empty")
                return False
        else:
            print("ADF is not supported")
            return False
            
    except twain.excTWCC_CAPUNSUPPORTED:
        print("ADF capability not supported")
        return False

def apply_settings_to_scanner(src):
    """Apply the current settings to the scanner source"""
    try:
        # Set basic scan parameters
        if current_settings['scan_mode'] == 'Color':
            src.set_capability(twain.ICAP_PIXELTYPE, twain.TWPT_RGB)
        elif current_settings['scan_mode'] == 'Grayscale':
            src.set_capability(twain.ICAP_PIXELTYPE, twain.TWPT_GRAY)
        else:  # Black & White
            src.set_capability(twain.ICAP_PIXELTYPE, twain.TWPT_BW)
        
        src.set_capability(twain.ICAP_XRESOLUTION, float(current_settings['resolution']))
        src.set_capability(twain.ICAP_YRESOLUTION, float(current_settings['resolution']))
        
        # Set document size (simplified)
        if current_settings['document_size'] == 'A4':
            src.set_capability(twain.ICAP_SUPPORTEDSIZES, twain.TWSS_A4)
        
        # Set brightness and contrast if supported
        src.set_capability(twain.ICAP_BRIGHTNESS, float(current_settings['brightness']))
        src.set_capability(twain.ICAP_CONTRAST, float(current_settings['contrast']))
        
        # Set auto crop if supported
        if current_settings['auto_crop']:
            src.set_capability(twain.ICAP_AUTOMATICBORDERDETECTION, True)
        
    except twain.excTWCC_CAPUNSUPPORTED:
        print("Some capabilities are not supported by this scanner")

def process_scanned_image(img):
    """Handle the scanned image (save or display)"""
    global scanned_image
    
    # Save to file if destination is set to file
    if current_settings['destination'] == 'File' and current_settings['file_path']:
        file_ext = current_settings['file_format'].lower()
        if file_ext == 'jpeg':
            file_ext = 'jpg'
        # Add timestamp to filename for ADF scans
        timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S_%f")
        img.save(f"{current_settings['file_path']}_{timestamp}.{file_ext}")
    
    # Display in UI (only the last image for ADF)
    width, height = img.size
    factor = 600.0 / width
    scanned_image = PIL.ImageTk.PhotoImage(img.resize(size=(int(width * factor), int(height * factor))))
    image_frame.destroy()
    ttk.Label(root, image=scanned_image).pack(side="left", fill="both", expand=1)

def scan():
    global scanned_image
    with twain.SourceManager(root) as sm:
        src = sm.open_source()
        if src:
            try:
                # Check ADF support
                adf_supported = check_adf_support(src)
                
                # Apply settings before scanning
                apply_settings_to_scanner(src)
                
                if adf_supported:
                    # Enable ADF mode
                    src.set_capability(twain.CAP_FEEDERENABLED, True)
                    src.set_capability(twain.CAP_AUTOFEED, True)
                    print("Scanning using ADF mode...")
                else:
                    print("Scanning in flatbed mode...")
                
                # Scan loop for ADF (will scan once if flatbed)
                while True:
                    src.request_acquire(show_ui=False, modal_ui=False)
                    (handle, remaining_count) = src.xfer_image_natively()
                    
                    if handle is None:
                        break
                        
                    bmp_bytes = twain.dib_to_bm_file(handle)
                    img = PIL.Image.open(BytesIO(bmp_bytes), formats=["bmp"])
                    process_scanned_image(img)
                    
                    # Break if no more documents in ADF
                    if remaining_count == 0:
                        break
                        
            except Exception as e:
                messagebox.showerror("Scan Error", f"Error during scanning: {e}")
            finally:
                src.destroy()
        else:
            messagebox.showwarning("Warning", "No scanner selected")

def test_adf_support():
    """Test if ADF is supported and show result in messagebox"""
    with twain.SourceManager(root) as sm:
        src = sm.open_source()
        if src:
            try:
                # Check basic ADF support
                try:
                    has_adf = src.get_capability(twain.CAP_FEEDER)
                except:
                    has_adf = False
                
                # Check more detailed ADF capabilities
                capabilities = {
                    'CAP_FEEDER': has_adf,
                    'CAP_FEEDERENABLED': False,
                    'CAP_FEEDERLOADED': False,
                    'CAP_AUTOFEED': False,
                    'CAP_FEEDERPREP': False
                }
                
                for cap in capabilities.keys():
                    try:
                        capabilities[cap] = src.get_capability(getattr(twain, cap))
                    except:
                        pass
                
                # Build results message
                result_msg = "ADF Test Results:\n\n"
                result_msg += f"Basic ADF Support: {'Yes' if capabilities['CAP_FEEDER'] else 'No'}\n"
                result_msg += f"ADF Enabled: {'Yes' if capabilities['CAP_FEEDERENABLED'] else 'No'}\n"
                result_msg += f"Documents Loaded: {'Yes' if capabilities['CAP_FEEDERLOADED'] else 'No'}\n"
                result_msg += f"Auto-feed Available: {'Yes' if capabilities['CAP_AUTOFEED'] else 'No'}\n"
                result_msg += f"Needs Preparation: {'Yes' if capabilities['CAP_FEEDERPREP'] else 'No'}\n"
                
                messagebox.showinfo("ADF Test", result_msg)
                
            except Exception as e:
                messagebox.showerror("Error", f"Error testing ADF: {e}")
            finally:
                src.destroy()
        else:
            messagebox.showwarning("Warning", "No scanner selected")

def browse_file():
    filename = filedialog.asksaveasfilename(
        defaultextension=f".{current_settings['file_format'].lower()}",
        filetypes=[(f"{current_settings['file_format']} files", f"*.{current_settings['file_format'].lower()}")]
    )
    if filename:
        current_settings['file_path'] = filename
        file_path_var.set(filename)

def update_setting(setting_name, value):
    current_settings[setting_name] = value
    if setting_name == 'file_format' and current_settings['file_path']:
        # Update file extension if file path exists
        base_path = current_settings['file_path'].rsplit('.', 1)[0]
        current_settings['file_path'] = base_path
        file_path_var.set(base_path)

def create_settings_panel(parent):
    # Scan Mode
    ttk.Label(parent, text="Scan Mode:").grid(row=0, column=0, sticky='w')
    scan_mode = ttk.Combobox(parent, values=['Color', 'Grayscale', 'Black & White'], state='readonly')
    scan_mode.set(current_settings['scan_mode'])
    scan_mode.grid(row=0, column=1, sticky='ew')
    scan_mode.bind('<<ComboboxSelected>>', lambda e: update_setting('scan_mode', scan_mode.get()))
    
    # Resolution
    ttk.Label(parent, text="Resolution (DPI):").grid(row=1, column=0, sticky='w')
    resolution = ttk.Combobox(parent, values=[75, 150, 300, 600, 1200], state='readonly')
    resolution.set(current_settings['resolution'])
    resolution.grid(row=1, column=1, sticky='ew')
    resolution.bind('<<ComboboxSelected>>', lambda e: update_setting('resolution', int(resolution.get())))
    
    # Document Size
    ttk.Label(parent, text="Document Size:").grid(row=2, column=0, sticky='w')
    doc_size = ttk.Combobox(parent, values=['A4', 'Letter', 'Legal', 'Auto'], state='readonly')
    doc_size.set(current_settings['document_size'])
    doc_size.grid(row=2, column=1, sticky='ew')
    doc_size.bind('<<ComboboxSelected>>', lambda e: update_setting('document_size', doc_size.get()))
    
    # Document Type
    ttk.Label(parent, text="Document Type:").grid(row=3, column=0, sticky='w')
    doc_type = ttk.Combobox(parent, values=['Normal', 'Text', 'Photo', 'Magazine'], state='readonly')
    doc_type.set(current_settings['document_type'])
    doc_type.grid(row=3, column=1, sticky='ew')
    doc_type.bind('<<ComboboxSelected>>', lambda e: update_setting('document_type', doc_type.get()))
    
    # Auto Crop
    auto_crop = tk.BooleanVar(value=current_settings['auto_crop'])
    ttk.Checkbutton(parent, text="Auto Crop", variable=auto_crop, 
                   command=lambda: update_setting('auto_crop', auto_crop.get())).grid(row=4, column=0, columnspan=2, sticky='w')
    
    # Brightness
    ttk.Label(parent, text="Brightness:").grid(row=5, column=0, sticky='w')
    brightness = ttk.Scale(parent, from_=-100, to=100, value=current_settings['brightness'])
    brightness.grid(row=5, column=1, sticky='ew')
    brightness.bind('<ButtonRelease-1>', lambda e: update_setting('brightness', brightness.get()))
    
    # Contrast
    ttk.Label(parent, text="Contrast:").grid(row=6, column=0, sticky='w')
    contrast = ttk.Scale(parent, from_=-100, to=100, value=current_settings['contrast'])
    contrast.grid(row=6, column=1, sticky='ew')
    contrast.bind('<ButtonRelease-1>', lambda e: update_setting('contrast', contrast.get()))
    
    # Destination
    ttk.Label(parent, text="Destination:").grid(row=7, column=0, sticky='w')
    dest_frame = ttk.Frame(parent)
    dest_frame.grid(row=7, column=1, sticky='ew')
    
    destination = tk.StringVar(value=current_settings['destination'])
    ttk.Radiobutton(dest_frame, text="Screen", variable=destination, value="Screen",
                   command=lambda: update_setting('destination', destination.get())).pack(side='left')
    ttk.Radiobutton(dest_frame, text="File", variable=destination, value="File",
                   command=lambda: update_setting('destination', destination.get())).pack(side='left')
    
    # File Format
    ttk.Label(parent, text="File Format:").grid(row=8, column=0, sticky='w')
    file_format = ttk.Combobox(parent, values=['JPEG', 'PNG', 'BMP', 'TIFF'], state='readonly')
    file_format.set(current_settings['file_format'])
    file_format.grid(row=8, column=1, sticky='ew')
    file_format.bind('<<ComboboxSelected>>', lambda e: update_setting('file_format', file_format.get()))
    
    # File Path
    ttk.Label(parent, text="File Path:").grid(row=9, column=0, sticky='w')
    global file_path_var
    file_path_var = tk.StringVar(value=current_settings['file_path'])
    path_frame = ttk.Frame(parent)
    path_frame.grid(row=9, column=1, sticky='ew')
    ttk.Entry(path_frame, textvariable=file_path_var).pack(side='left', fill='x', expand=True)
    ttk.Button(path_frame, text="Browse...", command=browse_file).pack(side='left')
    
    # Scan Button
    ttk.Button(parent, text="Scan", command=scan).grid(row=10, column=0, columnspan=2, pady=10)
    
    # ADF Test Button
    ttk.Button(parent, text="Test ADF Support", command=test_adf_support).grid(row=11, column=0, columnspan=2, pady=5)

# Main application setup
logging.basicConfig(level=logging.DEBUG)
root = tk.Tk()
root.title("Scanner Application with ADF Test")

# Main frame
main_frame = ttk.Frame(root, padding=10)
main_frame.pack(fill='both', expand=True)

# Settings panel on the left
settings_frame = ttk.LabelFrame(main_frame, text="Scanner Settings", padding=10)
settings_frame.pack(side='left', fill='y')

# Image display area on the right
image_frame = ttk.Frame(main_frame)
image_frame.pack(side='right', fill='both', expand=True)

create_settings_panel(settings_frame)

root.mainloop()

I have this for only flat bet mode.
But I want ADF mode using python.

Anybody experieced?

Reasons:
  • RegEx Blacklisted phrase (1): I want
  • Long answer (-1):
  • Has code block (-0.5):
  • Ends in question mark (2):
  • Low reputation (1):
Posted by: ricky Feli