import os from PIL import Image from PIL.ExifTags import TAGS, GPSTAGS import UtilPack as util # EXIF 데이터에서 사진이 찍힌 날자와 시간을 가져온다 def GetDateInfo(ImgPath): img = _imageOpen(ImgPath) if None == img: return "", 0.0, 0.0 dataEXIF = _getEXIFData(img) date = _getDateEXIF(dataEXIF) dataGPS = _parseGPSInfo(dataEXIF) lat, lon = _getlatlon(dataGPS) return date, lat, lon def ProcessImg(imgAbsPath, fRatio, nQlt = 85, bOrientApy = True): # dirSave = "Thumb" dirpath, filename = os.path.split(imgAbsPath) parenDir = os.path.dirname(dirpath) dirThumb = os.path.join(parenDir, dirSave) finalPath = os.path.join(dirThumb, filename) # 설정은 상관없이 이전에 리사이즈 해 둔 것이 있으면 경로 반환 if True == os.path.exists(finalPath): #print(f"[] -> {finalPath}") return finalPath img = _imageOpen(imgAbsPath) if None == img: return imgAbsPath nRotate = 0 if True == bOrientApy: dataEXIF = _getEXIFData(img) nRotate = _getOrientationEXIF(dataEXIF) img = _rotateImg(img, nRotate) img = _resizeImg(img, fRatio) if False == os.path.exists(dirThumb): os.makedirs(dirThumb, 0o777) print(f"Thumb folder Created : {dirThumb}") img.save(finalPath, optimize=True, quality=nQlt) #print(f"{imgAbsPath} -> {finalPath}") return finalPath def _rotateImg(imgSrc, nRotate): if None == imgSrc: return imgSrc if not isinstance(imgSrc, Image.Image): #raise TypeError("Input must be a PIL Image object") print("Type Error") return imgSrc if 0 >= nRotate or 360 <= nRotate: return imgSrc imgRet = imgSrc.rotate(nRotate, expand=True) bbox = imgRet.getbbox() imgRet = imgRet.crop(bbox) return imgRet def _resizeImg(imgSrc, fRatio ): if None == imgSrc: return imgSrc if not isinstance(imgSrc, Image.Image): #raise TypeError("Input must be a PIL Image object") return imgSrc if 0 >= fRatio or 1.0 < fRatio: return imgSrc imgRet = imgSrc.resize((int(imgSrc.width * fRatio), int(imgSrc.height * fRatio))) return imgRet def _imageOpen(ImgPath): imgRet = None try: # 이미지 열기 시도 imgRet = Image.open(ImgPath) imgRet.load() # 이미지 파일을 실제로 로드하여 확인 util.DbgOut("Image open successful") # 이미지 처리 코드 추가 except FileNotFoundError: util.DbgOut(f"can't find Image': {ImgPath}") except OSError: util.DbgOut(f"Image broken or unsupported MIME: {ImgPath}") except Exception as e: util.DbgOut(f"unexpected error: {e}") return imgRet # 이미지에서 EXIF 데이터를 추출하여 딕셔너리 형태로 반환 def _getEXIFData(image): exif_data = {} try: info = image._getexif() if info: for tag, value in info.items(): decoded = TAGS.get(tag, tag) exif_data[decoded] = value except AttributeError: pass return exif_data def _getDateEXIF(exif_data): date_taken = exif_data.get('DateTimeOriginal') return date_taken # 0 : NoData # 1: "Landscape (normal) -> 0" # 3: "Landscape (upside down) -> 180" # 6: "Portrait (rotated 90° CW) -> 270" # 8: "Portrait (rotated 90° CCW) -> 90" def _getOrientationEXIF(exif_data): if exif_data is None: return 0 retValue = 0 # EXIF 태그에서 Orientation 추출 for tag, value in exif_data.items(): tag_name = TAGS.get(tag, tag) if tag_name == 'Orientation': if value == 3: retValue = 180 elif value == 6: retValue = 270 elif value == 8: retValue = 90 else: # value == 1: retValue = 0 break return retValue # EXIF 데이터에서 GPS 정보를 파싱하여 딕셔너리 형태로 반환 def _parseGPSInfo(exif_data): gps_info = {} if 'GPSInfo' in exif_data: for key in exif_data['GPSInfo'].keys(): decode = GPSTAGS.get(key, key) gps_info[decode] = exif_data['GPSInfo'][key] return gps_info # 도, 분, 초 형식의 GPS 데이터를 도 형식으로 변환 def _convertToDegrees(value): d = 0.0 if 0 < value[0]: d = float(value[0]) m = 0.0 if 0 < value[1]: m = float(value[1]) / 60.0 s = 0.0 if 0 < value[2]: s = float(value[2]) / 3600.0 return d + m + s # GPS 정보를 사용하여 위도와 경도를 도 형식으로 반환 def _getlatlon(gps_info): lat,lon = 0.0, 0.0 if 'GPSLatitude' in gps_info and 'GPSLatitudeRef' in gps_info: lat = _convertToDegrees(gps_info['GPSLatitude']) if gps_info['GPSLatitudeRef'] != 'N': lat = -lat if 'GPSLongitude' in gps_info and 'GPSLongitudeRef' in gps_info: lon = _convertToDegrees(gps_info['GPSLongitude']) if gps_info['GPSLongitudeRef'] != 'E': lon = -lon return lat, lon