컴퓨터

압축파일에 있는 이미지 파일들을 webp로 변환하는 소스코드와 프로그램

파이썬 코드임

다른 사람이 뿌린 오픈소스에 오류 안생기게 조금 수정했음
오류는 없고 오류가 뜬다면 이미지 파일 자체가 손상돼서 변환이 되지않는 경우라서

원래 그것도 변환되게 할 수 있는데 안하는게 나아서 패스함

 

# -*- coding:utf-8 -*-
from PIL import Image
import zipfile
from zipfile import ZipFile
import glob
import os
import shutil
import multiprocessing
import sys
import chardet # 인코딩 확인
from ctypes import windll, wintypes, byref

THUMBNAIL_NAME = '_thumbnail.png'

def unzip(source_file, dest_path):
    with zipfile.ZipFile(source_file, 'r') as zf:
        zipInfo = zf.infolist()
        for member in zipInfo:
            try:
                #print(chardet.detect(member.filename.encode()))
                #member.filename = member.filename.encode('cp437', errors='replace').decode('cp949', 'ignore')
                member.filename = member.filename.encode('cp437').decode('euc-kr', 'ignore')
                zf.extract(member, dest_path) #압축해제할 파일명, 압축해제할 경로
            except:
                try:
                    zf.extract(member, dest_path) #한글로 변환이 안 될시 그대로 변환
                except:
                    raise Exception(source_file + ' 파일명과 ' + dest_path + ' 경로가 잘못되었습니다.')
                #zf.extract(member, dest_path)
                #print(source_file)
                #raise Exception('what?!')

def modify_ctime(path, ctime):
    #https://stackoverflow.com/questions/4996405/how-do-i-change-the-file-creation-date-of-a-windows-file
    # Arbitrary example of a file and a date
    filepath = path
    epoch = ctime

    # Convert Unix timestamp to Windows FileTime using some magic numbers
    # See documentation: https://support.microsoft.com/en-us/help/167296
    timestamp = int((epoch * 10000000) + 116444736000000000)
    ctime = wintypes.FILETIME(timestamp & 0xFFFFFFFF, timestamp >> 32)

    # Call Win32 API to modify the file creation date
    handle = windll.kernel32.CreateFileW(filepath, 256, 0, None, 3, 128, None)
    windll.kernel32.SetFileTime(handle, byref(ctime), None, None)
    windll.kernel32.CloseHandle(handle)

def get_thread_number():
    number_of_thread = multiprocessing.cpu_count() - 1
    if number_of_thread == 0:
        return 1
    else:
        return number_of_thread

def split_to_chunks(image_paths, n):
    return [image_paths[i::n] for i in range(n)]

def convert_images(image_paths, options, shared_queue):
    for image_path in image_paths:
        image = Image.open(image_path)
        image.save(os.path.splitext(image_path)[0] + '.webp', method=6, lossless=options['lossless'], quality=options['quality'])

    for image_path in image_paths:
        os.remove(image_path)

    shared_queue.put(True)
    return

def generate_thumbnail(folder_path):
    MAX_SIZE = 640
    file_paths = []
    image_path = get_file_paths_by_extensions(folder_path, ['jpg', 'png', 'webp', 'gif'], file_paths)[0]

    # Generate thumbnail only if images exist
    if not image_path:
        return

    image = Image.open(image_path)
    width, height = image.size
    resize_ratio = min(MAX_SIZE/width, MAX_SIZE/height)
    resized_resolution = (int(width*resize_ratio), int(height*resize_ratio))
    thumbnail = image.resize(resized_resolution)
    thumbnail.save(os.path.join(folder_path, THUMBNAIL_NAME))

def get_file_paths_by_extensions(folder_path, extensions, file_paths):
    sub_folder_paths = os.listdir(folder_path)
    
    for sub_folder_path in sub_folder_paths:
        full_folder_path = os.path.join(folder_path, sub_folder_path)
        if os.path.isdir(full_folder_path):
            get_file_paths_by_extensions(full_folder_path, extensions, file_paths)
        elif os.path.isfile(full_folder_path):
            full_folder_name, full_folder_path_extension = os.path.splitext(full_folder_path)
            for extension in extensions:
                if full_folder_path_extension == "." + extension:
                    if not os.path.basename(full_folder_path) == THUMBNAIL_NAME: # 썸네일 파일 제외
                        file_paths.append(full_folder_path)
                        
    return file_paths

def recover_zip(folder_path, backup_path, zip_file_path):
    os.rename(backup_path, zip_file_path)
    shutil.rmtree(folder_path)
    raise NameError('Error during processing images')

def slimify(zip_file_path, options):
    print('Processing', zip_file_path)

    # Save file time info
    file_time = (os.stat(zip_file_path).st_atime, os.stat(zip_file_path).st_mtime)
    ctime = os.stat(zip_file_path).st_ctime

    # Unzip and make backup
    folder_path, extension = os.path.splitext(zip_file_path)
    #zip_path, zip_name = os.path.split(os.path.realpath(zip_file_path))
    #zip_file_path = os.path.join(zip_path, folder_path)
    #shutil.unpack_archive(zip_file_path, folder_path, 'zip') # 압축 파일의 전체 경로, 압축 해체할 폴더의 경로, 압축파일 형식
    unzip(zip_file_path, folder_path) # 압축 해제할 파일명, 압축 해제할 경로
    if not os.path.exists(folder_path):
        raise NameError('File name cannot be folder name')
    backup_path = zip_file_path + '.back'
    os.rename(zip_file_path, backup_path)

    # Find jpg or png
    file_paths = []
    image_paths = get_file_paths_by_extensions(folder_path, ['jpg', 'png', 'jpeg'], file_paths)
    image_path_chunks = split_to_chunks(image_paths, get_thread_number())

    # Generate thumbnail if needed
    if options['thumbnail']:
        generate_thumbnail(folder_path)

    # Convert images
    processes = []
    shared_queue = multiprocessing.Queue()
    for i in range(get_thread_number()):
        p = multiprocessing.Process(target=convert_images, args=(image_path_chunks[i], options, shared_queue))
        processes.append(p)
        p.start()
    for process in processes:
        process.join()

    # Check if error occured in multiprocessing
    if shared_queue.qsize() != get_thread_number():
        recover_zip(folder_path, backup_path, zip_file_path)
        return
    
    # Rezip the folder
    converted_zip_path = shutil.make_archive(folder_path, 'zip', folder_path)

    # Recover file time info
    os.utime(converted_zip_path, file_time)
    modify_ctime(converted_zip_path, ctime)


    # Remove old zip file and folder
    shutil.rmtree(folder_path)
    os.remove(backup_path)

def get_lossless_option():
    print('Select lossy or lossless (Default = lossy)')
    print('1. Lossy')
    print('2. Lossless')

    answer = input()

    if answer == '2':
        return True
    else:
        return False

def get_quality_option():
    DEFAULT = 80
    print('Select quality parameter 1-100 (Default = 80)')
    answer = input()

    if answer.isdecimal() == False:
        return DEFAULT
    
    answer_number = int(answer)

    if 0 < answer_number <= 100:
        return answer_number
    else:
        return DEFAULT

def get_thumbnail_option():
    print('Generate thumbnail? (for CBXShell) (Default = No)')
    print('1. Yes')
    print('2. No')

    answer = input()

    if answer == '1':
        return True
    else:
        return False

if __name__ == '__main__':
    # Windows exe support
    multiprocessing.freeze_support()

    options = {
        'lossless': get_lossless_option(),
        'quality': get_quality_option(),
        'thumbnail': get_thumbnail_option()
    }

    # In lossless mode, quality means speed
    if options['lossless']:
        options['quality'] = 100

    # Find zip files
    zip_file_paths = glob.glob('**/*.zip', recursive=True)
    print(zip_file_paths)

    # Process zip files
    for index, zip_file_path in enumerate(zip_file_paths):
        print('Processing', index, '/', len(zip_file_paths))
        try:
            slimify(zip_file_path, options)
        except Exception as err:
            print(f'Error during {zip_file_path}', err)
            with open('errorlog.txt', 'a+') as f:
                f.write(f'Error during {zip_file_path} {err}\n')

    print('Process finished')
    print('Press Enter to exit')
    input()

방주작업할 때 좆같이 느린 쓰레기 변환 프로그램에 고통 받으신 분들 이거 쓰세요

아래 이미지 파일 다운 받아서 jpg를 zip로 확장자 변경한 후 풀어서 압축파일과 실행파일 같이 넣어서 실행하세요

무분별한 사용은 차단될 수 있습니다.
번호 제목 글쓴이 추천 수 날짜 조회 수
180358 [컴퓨터] 이거 괜찮은 가격인가요? 1 죽업 0 17 분 전 14
180357 [잡담] 급해서 특급운송으로 주문했는데... 오브 0 18 분 전 16
180356 [컴퓨터] 사도 됨? 8 or5469 0 3 시간 전 80
180355 [모바일] 에어팟 프로 1세대 노이즈 캔슬링시 들리는 잡음 해결 방법 3 기승전치킨 0 5 시간 전 96
180354 [컴퓨터] RX7600 생각보다 잘만들었네? 7 Vv연옥의사신vV 0 6 시간 전 165
180353 [컴퓨터] 모니터가 FHD이면.. FHD이상은 차이없는거 아닌가? 2 ing 0 6 시간 전 128
180352 [견적] 컴 살까 하는데 견적 어떤가여 3 함박눈 0 8 시간 전 72
180351 [컴퓨터] 5700x3d 장착 후기 1 바숲 1 8 시간 전 120
180350 [잡담] U4025QW 도착! (WFHD 75 HZ -> WUHD 120HZ 한방 업글기) 3 냐하하하하 1 9 시간 전 86
180349 [견적] 노트북 처음 사보려고 하는데 어디서 어떻게 사야 좋을까요? 5 하늘을나는잉어킹 0 9 시간 전 49
180348 [컴퓨터] 요즘 윈도우 하는짓거리 너무싫어서 4 Vv연옥의사신vV 0 9 시간 전 152
180347 [모바일] 핏3 구매후 느낀점 2 타이거밤 0 10 시간 전 150
180346 [컴퓨터] 암드9천번대 및 5080존버 견적좀 봐주세여 16 사촌간부랄빨기 0 10 시간 전 100
180345 [프로그래밍] Exiftool 이거 일본어 못 읽는데 12 부터시작하는이세... 0 11 시간 전 125
180344 [잡담] 컴터 질렀다 32 사촌간부랄빨기 0 12 시간 전 155
180343 [컴퓨터] 모니터 화면 10 흙수저 0 12 시간 전 74
180342 [컴퓨터] SSD 문제 있을때 고칠 방법 뭐가 있을까? 4 베데엔차 0 12 시간 전 87
180341 [컴퓨터] 모니터가 QHD에 주사율 165hz 인데 이걸 적용이 안됨ㅠㅠ 31 야스그랜드마스터 0 13 시간 전 141
180340 [컴퓨터] 모니터 12v 어뎁터 필요한가요 전원 ㅈ 6 흙수저 0 13 시간 전 60
180339 [컴퓨터] 60>144hz도 체감 엄청 커? 10 청주리신 0 14 시간 전 208