PNG File Parser

g0ni·2024년 10월 22일

PNG File

목록 보기
2/2
import sys
import struct
from binascii import *

png_file_signature = b'\x89\x50\x4E\x47\x0D\x0A\x1A\x0A'
png_file_footer = b'\x49\x45\x4E\x44\xAE\x42\x60\x82'
chunklist = []

def png_ihdr_info(png_path):
    global png_file_signature
        
    try:
        with open(png_path, 'rb') as f:
            # PNG File Header Signature
            signature = f.read(8)
            if signature == png_file_signature:
                edit_signature = ' '.join([signature.hex()[i:i+2] for i in range(0, len(signature.hex()), 2)])
                print(f'\n# File Header signature (Magic Number)')
                print(f'{edit_signature}\n')
            else:
                print(f'PNG File Signature is not valid.')
                return False
                
            # PNG File Length
            length = f.read(4)
            
            # PNG Chunk Type
            chunk_type = f.read(4)
            
            # IHDR info
            print(f'# IHDR info')
            
            # IHDR Width
            width = f.read(4)
            int_width = int.from_bytes(width, byteorder='big')
            print(f'Width: {int_width}')
            
            # IHDR Height 
            height = f.read(4)
            int_height = int.from_bytes(height, byteorder='big')
            print(f'Height: {int_height}')
            
            # IHDR Bit Depth
            depth = f.read(1)
            int_depth = int.from_bytes(depth, byteorder='big')
            print(f'Bit depth: {int_depth}')
            
            # IHDR Color Type
            color_type = f.read(1)
            int_color_type = int.from_bytes(color_type, byteorder='big')
            
            match int_color_type:
                case 0:
                    print(f'Color Type: {int_color_type} (Grayscale)')
                case 2:
                    print(f'Color Type: {int_color_type} (RGB)')
                case 3:
                    print(f'Color Type: {int_color_type} Palette)')
                case 4:
                    print(f'Color Type: {int_color_type} (Grayscale with alpha)')
                case 6:
                    print(f'Color Type: {int_color_type} (RGB with alpha)')
                case _:
                    print(f'not matched')
            
            # IHDR Compression method
            compression_method = f.read(1)
            int_compression_method = int.from_bytes(compression_method, byteorder='big')
            print(f'Compression method: {int_compression_method}')
            
            # Filter method
            filter_method = f.read(1)
            int_filter_method = int.from_bytes(filter_method, byteorder='big')
            print(f'Filter method: {int_filter_method}')
            
            # Interlace method
            interface_method = f.read(1)
            int_interface_method = int.from_bytes(interface_method, byteorder='big')
            print(f'Interlace method: {int_interface_method}\n')
            
            return True
            
    except FileNotFoundError:
        print(f"File {png_path} can't find.")
        return False
    
def chunk_list(png_path):
    global png_file_signature
    global png_file_footer
    
    try:
        with open(png_path, 'rb') as f:
            
            f.seek(0)
            
            # PNG File Header Signature
            signature = f.read(8)
            if signature != png_file_signature:
                print(f'PNG File Signature is not valid.')
                return False
            
            while True:
                
                length = f.read(4)
                
                if len(length) == 0:
                    break  
                
                chunk_length = int.from_bytes(length, byteorder='big')
                chunk_type = f.read(4)
                chunklist.append(chunk_type)
                chunk_data = f.read(chunk_length)
                chunk_crc = f.read(4)
                
                if chunk_type == b'IEND':
                    footer = chunk_type + chunk_crc
                    edit_footer = ' '.join([footer.hex()[i:i+2] for i in range(0, len(signature.hex()), 2)])
                    
            print(f"# Chunk list")
            print(f"{chunklist}\n")
            
            print(f'# File Footer signature')
            print(f'{edit_footer}\n')
            
            return True
            
    except FileNotFoundError:
        print(f"File {png_path} can't find.")
        return False


if __name__=='__main__':
    # usage
    if len(sys.argv) != 2:
        print("usage : python ./png_parse.py ./png_path")
        sys.exit()

    # png path
    png_path = sys.argv[1]
    
    # def Check
    png_ihdr_info_CHK = png_ihdr_info(png_path)
    chunk_list_CHK = chunk_list(png_path)
    
    if png_ihdr_info_CHK and chunk_list_CHK:
        print(f'Chunk 영역 추출 완료.\n')
        print(f'프로그램 종료.')
profile
Let it rip!

0개의 댓글