from PIL import Image

image1 = Image.open('/content/nature.png')
image2=Image.open('/content/nature1.png')

image1

image2

image1.size

image1= image1.resize((300,200))

image1

image1.size

image2.size

def int2bin(rgb):
    
    #Will convert RGB pixel values from integer to binary
    #INPUT: An integer tuple (e.g. (220, 110, 96))
    #OUTPUT: A string tuple (e.g. ("00101010", "11101011", "00010110"))
    
    r, g, b = rgb
    return ('{0:08b}'.format(r),
            '{0:08b}'.format(g),
            '{0:08b}'.format(b))
    #Return converted r,g,b binary values separately..

def bin2int(rgb):
    
    #Will convert RGB pixel values from binary to integer.
    #Reverse of the first part.
  
    r, g, b = rgb
    return (int(r, 2),
            int(g, 2),
            int(b, 2))
    #return converted r,g,b integer values separately

r,g,b=int2bin((225,6,7))
r

r[:4]

print(g)
print(b)

bin2int(('11100001', '00000110', '00000111'))

def merge2rgb(rgb1,rgb2):
    
    #Will merge two RGB pixels using 4 least significant bits.
    #INPUT: A string tuple ( ("00101010", "11101011", "00010110")),another string tuple (e.g. ("00101010", "11101011", "00010110"))
    #OUTPUT: An integer tuple with the two RGB values merged
    #Will be merging the first four digits of first image and first four digits of 2nd image(i.e to be merged) as last four digits..
    

    r1,g1,b1=rgb1
    r2,g2,b2=rgb2

    return (r1[:4]+r2[:4],
             g1[:4]+g2[:4],
             b1[:4]+b2[:4]
          )

def merge2img(img1,img2):
  # The First image will be merged into the second image.


  image1=img1
  image2=img2
  #print('rahul')
  
  # Condition for merging
  if(image1.size[0]>image2.size[0] or image1.size[1]>image2.size[1]):
    print("Cannot merge as the size of 1st Image is greater than size of 2nd Image")
    return
  # Getting the pixel map of the two images

  pixel_tuple1 = image1.load()
  pixel_tuple2 = image2.load()

  #print(pixel_tuple1)
  #print(pixel_tuple2)

  # The new image that will be created.
  new_image = Image.new(image2.mode, image2.size) # Setting the size of Image 2 as Image 1 will be merged to Image 2.
  pixels_new = new_image.load()

  for row in range(image2.size[0]):
    for col in range(image2.size[1]):

        rgb1 = int2bin(pixel_tuple2[row, col])

        # Using a black pixel as default
        rgb2 = int2bin((0, 0, 0))

        # Converting the pixels of image 1 if condition is satisfied

        if(row <image1.size[0] and col< image1.size[1]):
          rgb2= int2bin(pixel_tuple1[row,col])


        merge_rgb= merge2rgb(rgb1,rgb2)

        pixels_new[row,col] = bin2int(merge_rgb) 

  #print('rahul')
  new_image.convert('RGB').save('merged1.jpg')
    
  return new_image   



 merge2img(image1,image2)

def unmerge(path):

    img=Image.open(path)

    # Loading the pixel map
    pixel_map = img.load()

    new_image = Image.new(img.mode, img.size)
    pixels_new = new_image.load()

    # Tuple used to store the image original size
    original_size = img.size

    for row in range(img.size[0]):
        for col in range(img.size[1]):
            # Get the RGB (as a string tuple) from the current pixel
            r, g, b = int2bin(pixel_map[row, col])

            # Extract the last 4 bits (corresponding to the hidden image)
            # Concatenate 4 zero bits because we are working with 8 bit values
            rgb = (r[4:] + "0000",
                   g[4:] + "0000",
                   b[4:] + "0000")

            # Convert it to an integer tuple
            pixels_new[row, col] = bin2int(rgb)

            # If this is a 'valid' position, store it
            # as the last valid position
            if pixels_new[row, col] != (0, 0, 0):
                original_size = (row + 1, col + 1)

    # Crop the image based on the 'valid' pixels
    new_image = new_image.crop((0, 0, original_size[0], original_size[1]))

    new_image.save('unmerged1.png')
    
    return new_image

unmerge('/content/merged1.jpg')

def merge2rgb2(rgb1, rgb2):
    
    r1, g1, b1 = rgb1
    r2, g2, b2 = rgb2
    rgb = (r1[:6] + r2[:2],
           g1[:6] + g2[:2],
           b1[:6] + b2[:2])
    return rgb

def merge2img2(img1, img2):

    image1=img1
    image2=img2
    #print('rahul')
  
    # Condition for merging
    if(image1.size[0]>image2.size[0] or image1.size[1]>image2.size[1]):
       print("Cannot merge as the size of 1st Image is greater than size of 2nd Image")
       return
  
  # Getting the pixel map of the two images
    pixel_tuple1 = image1.load()
    pixel_tuple2 = image2.load()

    #print(pixel_tuple1)
    #print(pixel_tuple2)

    # The new image that will be created.
    new_image = Image.new(image2.mode, image2.size) # Setting the size of Image 2 as Image 1 will be merged to Image 2.
    pixels_new = new_image.load()

    for row in range(image2.size[0]):
      for col in range(image2.size[1]):

        rgb1 = int2bin(pixel_tuple2[row, col])

        # Using a black pixel as default
        rgb2 = int2bin((0, 0, 0))

        # Converting the pixels of image 1 if condition is satisfied

        if(row <image1.size[0] and col< image1.size[1]):
          rgb2= int2bin(pixel_tuple1[row,col])


        merge_rgb= merge2rgb2(rgb1,rgb2)

        pixels_new[row,col] = bin2int(merge_rgb) 

    #print('rahul')
    new_image.convert('RGB').save('merged2.jpg')
    
    return new_image

def unmerge2(img):
    
    pixel_map = img.load()

    new_image = Image.new(img.mode, img.size)
    pixels_new = new_image.load()

    
    original_size = img.size

    for row in range(img.size[0]):
        for col in range(img.size[1]):
            r, g, b = int2bin(pixel_map[row, col])

            # Extracting the last 6 bits (corresponding to the hidden image) and adding zeroes to increase the brightness.
            
            rgb = (r[6:] + "000000",
                   g[6:] + "000000",
                   b[6:] + "000000")

            # Convert it to an integer tuple
            pixels_new[row, col] = bin2int(rgb)

           #If this is a 'valid' position, store it as a last valid option
            if pixels_new[row, col] != (0, 0, 0):
                original_size = (row + 1, col + 1)

    # Crop the image based on the 'valid' pixels
    new_image = new_image.crop((0, 0, original_size[0], original_size[1]))

    return new_image

merged_image2 = merge2img2(image1,image2)
merged_image2

unmerged_image2 = unmerge2(merged_image2)
unmerged_image2