import base64 import pyperclip import win32clipboard from io import BytesIO from PIL import Image import requests import numpy as np import cv2 import time import random class base64TOImage: def __init__(self, app, logger, browser_controller): self.app = app self.logger = logger self.browser_controller = browser_controller # BrowserController 인스턴스를 전달받음 def get_clipboard_data(self): """클립보드의 텍스트 데이터를 가져옵니다.""" try: return pyperclip.paste() # 클립보드의 텍스트 데이터를 가져옴 except Exception as e: self.logger.debug(f"클립보드 데이터를 가져오는 중 오류 발생: {e}") return None # def set_image_to_clipboard(self, image): # """이미지를 클립보드에 넣는 함수 (Windows 전용)""" # output = BytesIO() # image.save(output, "BMP") # data = output.getvalue()[14:] # BMP 헤더 제거 # output.close() # # 클립보드에 이미지 데이터 넣기 # win32clipboard.OpenClipboard() # win32clipboard.EmptyClipboard() # win32clipboard.SetClipboardData(win32clipboard.CF_DIB, data) # win32clipboard.CloseClipboard() def set_image_to_clipboard(self, image): """이미지를 클립보드에 넣는 함수 (Windows 전용, 5% 크롭 후)""" # 이미지의 크기 계산 (5% 크롭) width, height = image.size left = width * 0.05 top = height * 0.05 right = width * 0.95 bottom = height * 0.95 # 5% 크롭 적용 cropped_image = image.crop((left, top, right, bottom)) # 이미지를 BMP 형식으로 변환하여 클립보드에 넣기 output = BytesIO() cropped_image.save(output, "BMP") data = output.getvalue()[14:] # BMP 헤더 제거 output.close() # 클립보드에 이미지 데이터 넣기 win32clipboard.OpenClipboard() win32clipboard.EmptyClipboard() win32clipboard.SetClipboardData(win32clipboard.CF_DIB, data) win32clipboard.CloseClipboard() self.logger.debug("5% 크롭된 이미지가 클립보드에 저장되었습니다.") def base64_to_image(self, base64_data): """Base64 데이터를 이미지로 변환하는 함수""" if base64_data.startswith('data:image'): header, encoded = base64_data.split(',', 1) img_data = base64.b64decode(encoded) image = Image.open(BytesIO(img_data)) return image else: self.logger.debug("유효하지 않은 Base64 이미지 데이터입니다.") return None def download_image_from_url(self, url, max_retries=3): """URL에서 이미지를 다운로드하고 PIL 이미지 객체로 반환""" headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", "Accept-Language": "en-US,en;q=0.9", "Accept-Encoding": "gzip, deflate, br", "DNT": "1", # Do Not Track 요청 헤더 "Connection": "keep-alive", "Upgrade-Insecure-Requests": "1", "Cache-Control": "max-age=0" } retries = 0 while retries < max_retries: try: self.logger.debug(f"이미지 URL 다운로드 중: {url}") response = requests.get(url, headers=headers, stream=True) # 상태 코드가 200이 아니면 재시도 if response.status_code == 200: # OpenCV로 이미지를 로드하여 변환 image = np.asarray(bytearray(response.content), dtype="uint8") image = cv2.imdecode(image, cv2.IMREAD_COLOR) # OpenCV에서 이미지를 PIL로 변환 if image is not None: pil_image = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)) return pil_image else: self.logger.debug(f"이미지 파일 형식이 올바르지 않습니다. 대상 URL: {url}") return None else: self.logger.debug(f"이미지 로딩 실패, HTTP 상태 코드: {response.status_code}. 재시도 {retries + 1}/{max_retries}") retries += 1 time.sleep(random.randint(2, 5)) # 2~5초 대기 후 재시도 except Exception as e: self.logger.debug(f"이미지 로딩 중 오류 발생: {e}. 재시도 {retries + 1}/{max_retries}") retries += 1 time.sleep(random.randint(2, 5)) # 예외 발생 시 대기 후 재시도 self.logger.debug("이미지 다운로드 최대 재시도 횟수를 초과했습니다.") return None # def process_clipboard(self, original_url): # """클립보드의 내용을 처리하고, 필요한 경우 이미지 변환 또는 URL 이미지 복사""" # clipboard_data = self.get_clipboard_data() # if clipboard_data.startswith('data:image'): # # 클립보드에 있는 Base64 데이터를 이미지로 변환 # image = self.base64_to_image(clipboard_data) # if image: # self.logger.debug("Base64 이미지 변환 성공, 클립보드에 다시 저장 중...") # self.set_image_to_clipboard(image) # self.logger.debug("이미지가 클립보드에 저장되었습니다.") # else: # self.logger.debug("Base64 이미지 변환 실패.") # elif clipboard_data.strip() == "html > whale-ocr": # # 'html > whale-ocr' 감지 시 원본 이미지 URL에서 이미지를 다운로드하여 클립보드에 복사 # if original_url: # image = self.download_image_from_url(original_url) # if image: # self.logger.debug("원본 이미지 다운로드 성공, 클립보드에 다시 저장 중...") # self.set_image_to_clipboard(image) # self.logger.debug("원본 이미지가 클립보드에 저장되었습니다.") # else: # self.logger.debug("원본 이미지 다운로드 실패.") # else: # self.logger.debug("원본 이미지 URL을 찾을 수 없습니다.") # else: # self.logger.debug("클립보드에 Base64 이미지나 'html > whale-ocr' 데이터가 없습니다.") def process_clipboard(self, original_url): """클립보드의 내용을 처리하고, 필요한 경우 이미지 변환 또는 URL 이미지 복사""" clipboard_data = self.get_clipboard_data() if clipboard_data.startswith('data:image'): # 클립보드에 있는 Base64 데이터를 이미지로 변환 image = self.base64_to_image(clipboard_data) if image: self.logger.debug("Base64 이미지 변환 성공, 클립보드에 다시 저장 중...") self.set_image_to_clipboard(image) self.logger.debug("이미지가 클립보드에 저장되었습니다.") else: self.logger.debug("Base64 이미지 변환 실패.") elif clipboard_data.strip() == "html > whale-ocr": # 'html > whale-ocr' 감지 시 원본 이미지 URL에서 이미지를 다운로드하여 클립보드에 복사 if original_url: image = self.download_image_from_url(original_url) if image: self.logger.debug("원본 이미지 다운로드 성공, 클립보드에 다시 저장 중...") self.set_image_to_clipboard(image) self.logger.debug("원본 이미지가 클립보드에 저장되었습니다.") else: self.logger.debug("원본 이미지 다운로드 실패.") else: self.logger.debug("원본 이미지 URL을 찾을 수 없습니다.") elif clipboard_data: # 클립보드 내용이 이미지인 경우, 이미지 크기를 검사 image = self.base64_to_image(clipboard_data) if image: width, height = image.size self.logger.debug(f"클립보드에 있는 이미지 크기: {width}x{height}") # 이미지가 가로나 세로 중 하나라도 200픽셀 이하인 경우 원본 이미지 다운로드 if width <= 200 or height <= 200: if original_url: self.logger.debug(f"이미지 크기가 {width}x{height}로 200픽셀 이하입니다. 원본 이미지 다운로드 중...") original_image = self.download_image_from_url(original_url) if original_image: self.logger.debug("원본 이미지 다운로드 성공, 클립보드에 다시 저장 중...") self.set_image_to_clipboard(original_image) self.logger.debug("원본 이미지가 클립보드에 저장되었습니다.") else: self.logger.debug("원본 이미지 다운로드 실패.") else: self.logger.debug("원본 이미지 URL을 찾을 수 없습니다.") else: self.logger.debug("이미지 크기가 200픽셀 이상입니다. 처리할 필요가 없습니다.") else: self.logger.debug("클립보드에 있는 데이터는 이미지가 아닙니다.") else: self.logger.debug("클립보드에 Base64 이미지나 'html > whale-ocr' 데이터가 없습니다.")