Advertisement
Kitomas

data encoder and decoder thing

May 23rd, 2025
168
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.65 KB | None | 0 0
  1. ''' ------------------------------------------------------------------------ '''
  2. ''' ------------------------------------------------------------------------ '''
  3. #"steganography_encoder_decoder_2025-05-22\embed_decode.py":
  4. #!/usr/bin/env python3
  5.  
  6. #usage example: "py embed_encode.py img_file.png [-noexecute]"
  7.  
  8. from sys import argv, stderr
  9. from os import system as cmd
  10. from math import floor
  11. from os.path import exists, splitext as split_file_extension
  12. from pprint import pprint
  13. from PIL import Image
  14. from time import time, sleep
  15. import subprocess
  16.  
  17.  
  18.  
  19. def errFatal(errorString, returnCode = -1):
  20.     print('ERROR: '+errorString, file=stderr)
  21.     exit(returnCode)
  22.    
  23. def rnd(x): return floor(x+0.5) # Python's built-in rounding is stupid
  24.  
  25. def toInt(x):
  26.     try:              return rnd(eval(x))
  27.     except Exception: return None
  28.  
  29.  
  30.  
  31. fileName_img  = argv[ 1] if len(argv) > 1 else None # Input image filename
  32. noExecute_str = argv[-1] if len(argv) > 2 else None
  33. noExecute = False
  34.  
  35. if __name__ == '__main__':
  36.     if not fileName_img: exit(0) # No file given; exit early
  37.     if noExecute_str and noExecute_str == '-noexecute': noExecute = True
  38.  
  39.  
  40.  
  41. img    = None # Image object
  42. width  = None
  43. height = None
  44.  
  45. def get_channel_bit(n):
  46.     global img
  47.     global width
  48.    
  49.     which_channel = n%3
  50.     n //= 3 # Integer divide
  51.  
  52.     x = n%width
  53.     n //= width
  54.  
  55.     y = n
  56.  
  57.     r,g,b = img.getpixel((x,y))
  58.  
  59.     if   which_channel == 0: return r&1
  60.     elif which_channel == 1: return g&1
  61.     else                   : return b&1
  62.  
  63.  
  64.  
  65. if __name__ == '__main__':
  66.     img = Image.open(fileName_img).convert('RGB')
  67.     width, height = img.size
  68.    
  69.     numHeaderBits = (4+4)*8
  70.     data = []
  71.    
  72.     # Get the data's file extension and size, in bytes
  73.     for i in range(numHeaderBits):
  74.         bit = i%8
  75.         if bit == 0: data.append(0)
  76.         data[-1] |= get_channel_bit(i)<<bit
  77.        
  78.     dataExt = str(bytes(data[0:4]), 'ascii').rstrip('\x00')
  79.     dataLen = int.from_bytes(bytes(data[4:8]), 'little')
  80.     data = []
  81.  
  82.    
  83.    
  84.     # Get rest of data
  85.     for i in range(numHeaderBits, numHeaderBits+dataLen*8):
  86.         bit = i%8
  87.         if bit == 0: data.append(0)
  88.         data[-1] |= get_channel_bit(i)<<bit
  89.        
  90.     data_bytes = bytes(data)
  91.    
  92.     # Write data to file
  93.     fileName_out = 'data_out.' + dataExt
  94.     file = open(fileName_out, 'wb')
  95.     file.write(data_bytes)
  96.     file.close()
  97.    
  98.    
  99.    
  100.     # This is potentially dangerous!
  101.     # Only execute programs you know are safe!
  102.     if not noExecute:
  103.         if dataExt.lower() == 'py':
  104.             exec(str(data_bytes, 'ascii'))
  105.        
  106.         elif dataExt.lower() == 'exe':
  107.             pArgs = [ '.\\'+fileName_out, f'"{fileName_img}"' ]
  108.            
  109.             proc = subprocess.Popen(pArgs, shell=True)
  110.             while proc.poll() == None: sleep(0.02)
  111.  
  112.             pExitCode = proc.poll()
  113.             pOutput, pError = proc.communicate() # (pError is left unused)
  114.            
  115.             if len(pOutput) != 0: print(pOutput.decode("utf-8"))
  116.            
  117.             if pExitCode != 0: exit(pExitCode)
  118.            
  119.  
  120.  
  121.  
  122.  
  123. ''' ------------------------------------------------------------------------ '''
  124. ''' ------------------------------------------------------------------------ '''
  125. #"steganography_encoder_decoder_2025-05-22\embed_encode.py":
  126. #!/usr/bin/env python3
  127.  
  128. #usage example: "py embed_encode.py data_file.bin img_file.png"
  129.  
  130. from sys import argv, stderr
  131. from os import system as cmd
  132. from math import floor
  133. from os.path import exists, splitext as split_file_extension
  134. from pprint import pprint
  135. from PIL import Image
  136. from random import random
  137. from time import time
  138.  
  139.  
  140.  
  141. def errFatal(errorString, returnCode = -1):
  142.     print('ERROR: '+errorString, file=stderr)
  143.     exit(returnCode)
  144.    
  145. def rnd(x): return floor(x+0.5) # Python's built-in rounding is stupid
  146.  
  147. def toInt(x):
  148.     try:              return rnd(eval(x))
  149.     except Exception: return None
  150.    
  151. def append_filename(name, append):
  152.     root, ext = split_file_extension(name)
  153.     return root + append + ext
  154.  
  155.  
  156.  
  157. fileName_dat = argv[1] if len(argv) > 1 else None # Data to be embedded filename
  158. fileName_img = argv[2] if len(argv) > 2 else None # Input image filename
  159. fileName_out = argv[3] if len(argv) > 3 else None # Output image filename
  160. fileExt_dat = None # File extension of data filename
  161.  
  162. if __name__ == '__main__':
  163.     if not fileName_dat: errFatal('First argument must be data file path!')
  164.     if not fileName_img: errFatal('First argument must be image file path!')
  165.     if not fileName_out: fileName_out = append_filename(fileName_img, '_output')
  166.     dummyVariable, fileExt_dat = split_file_extension(fileName_dat)
  167.    
  168.     if not exists(fileName_dat): errFatal(f'"{fileName_dat}" doesn\'t exist!')
  169.     if not exists(fileName_img): errFatal(f'"{fileName_img}" doesn\'t exist!')
  170.  
  171.  
  172.  
  173.  
  174.  
  175. data   = None # List of byte values, in the form of ints (0-255)
  176. img    = None # Image object
  177. width  = None
  178. height = None
  179.  
  180.  
  181.  
  182. def get_channel_value(n):
  183.     global img
  184.     global width
  185.  
  186.     which_channel = n%3
  187.     n //= 3 # Integer divide
  188.    
  189.     x = n%width
  190.     n //= width
  191.    
  192.     y = n
  193.  
  194.     r,g,b = img.getpixel((x,y))
  195.    
  196.     if   which_channel == 0: return r
  197.     elif which_channel == 1: return g
  198.     else                   : return b
  199.  
  200.  
  201.  
  202. def set_channel_value(n, v):
  203.     global img
  204.     global width
  205.  
  206.     which_channel = n%3
  207.     n //= 3
  208.    
  209.     x = n%width
  210.     n //= width
  211.    
  212.     y = n
  213.  
  214.     r,g,b = img.getpixel((x,y))
  215.    
  216.     if   which_channel == 0: r = v
  217.     elif which_channel == 1: g = v
  218.     else                   : b = v
  219.    
  220.     img.putpixel((x,y), (r,g,b))
  221.  
  222.  
  223.  
  224. def get_data_bit(n, d):
  225.     which_bit = n%8
  226.     n //= 8
  227.    
  228.     which_byte = d[n]
  229.     return (which_byte>>which_bit)&1
  230.  
  231.  
  232.  
  233.  
  234.  
  235. if __name__ == '__main__':
  236.     file_dat = open(fileName_dat, 'rb')
  237.     data = list(file_dat.read())
  238.     file_dat.close()
  239.     if len(data) > 0xFFFFFFFF:
  240.         errFatal(f'Data size ({len(data)}) > {0xFFFFFFFF}')
  241.    
  242.     img = Image.open(fileName_img).convert('RGB')
  243.     width, height = img.size
  244.  
  245.     maxSize = (width*height*3)/8 - 8
  246.     print(f'Percent of max data size: {floor((len(data)/maxSize)*10000)/100}%')
  247.  
  248.     if len(data) > maxSize:
  249.         errFatal(f'Data size ({len(data)}) > (width*height*3)/8-8 ({maxSize})')
  250.  
  251.     if len(fileExt_dat) > 0  and  fileExt_dat[0:1] == '.':
  252.         fileExt_dat = fileExt_dat[1:]
  253.    
  254.     fileExt_padded = fileExt_dat.ljust(4, chr(0))[0:4]
  255.     fileExt_bytes = list(bytes(fileExt_padded, 'ascii')) # List of 0-255 ints
  256.    
  257.     dataLen_bytes = list(len(data).to_bytes(4,'little'))  # List of 0-255 ints
  258.    
  259.    
  260.    
  261.     # Write the file extension of the data file (the first 4 chars at, least)
  262.     for i in range(len(fileExt_bytes)*8):
  263.         # Get channel value, before unsetting the lowest bit
  264.         v = get_channel_value(i) & (~1)
  265.        
  266.         # Replace lowest bit of v with the relevant data bit
  267.         v |= get_data_bit(i, fileExt_bytes)
  268.        
  269.         # Set the relevant channel value to v
  270.         set_channel_value(i, v)
  271.  
  272.  
  273.  
  274.     # Write the size of the data file, in bytes (as a 32-bit unsigned integer)
  275.     add_to = len(fileExt_bytes)*8
  276.    
  277.     for i in range(len(dataLen_bytes)*8):
  278.         v  = get_channel_value(i+add_to) & (~1)
  279.         v |= get_data_bit(i, dataLen_bytes)
  280.         set_channel_value(i+add_to, v)
  281.  
  282.  
  283.  
  284.     # Write the actual data
  285.     add_to += len(dataLen_bytes)*8
  286.  
  287.     for i in range(len(data)*8):
  288.         v = get_channel_value(i+add_to) & (~1)
  289.         v |= get_data_bit(i, data)
  290.         set_channel_value(i+add_to, v)
  291.    
  292.    
  293.  
  294.     img.save(fileName_out)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement