"""
autos.py

Tworzenie autostereogramów

Autor: Mahesh Venkitachalam
"""

import sys, random, argparse
from PIL import Image, ImageDraw

# tworzenie przykładu odstępów (głębi)
def createSpacingDepthExample():
    tiles = [Image.open('test/a.png'), Image.open('test/b.png'), 
             Image.open('test/c.png')]
    img = Image.new('RGB', (600, 400), (0, 0, 0))
    spacing = [10, 20, 40]
    for j, tile in enumerate(tiles):
        for i in range(8):
            img.paste(tile, (10 + i*(100 + j*10), 10 + j*100))
    img.save('sdepth.png')

# tworzenie obrazu wypełnionego przypadkowymi punktami
def createRandomTile(dims):
  # tworzenie obrazu
  img = Image.new('RGB', dims)
  draw = ImageDraw.Draw(img)
  # ustawianie promienia losowego okręgu na 1%
  # szerokości lub wysokości, w zależności od tego, co jest mniejsze
  r = int(min(*dims)/100)
  # liczba okręgów
  n = 1000
  # rysowanie losowych okręgów
  for i in range(n):
    # -r zapewnia pozostanie okręgó w środku i to, że nie będą one przycięte na
	# brzegach obrazu, żeby wyglądało to lepiej po wypełnieniu kafelkami
    x, y = random.randint(0, dims[0]-r), random.randint(0, dims[1]-r)
    fill = (random.randint(0, 255), random.randint(0, 255), 
            random.randint(0, 255))
    draw.ellipse((x-r, y-r, x+r, y+r), fill)
  # zwracanie obrazu
  return img

# wykorzystanie pliku graficznego jako kafelka do utworzenia pośredniego obrazu o ustalonych wymiarach
def createTiledImage(tile, dims):
  # tworzenie nowego obrazu
  img = Image.new('RGB', dims)
  W, H = dims
  w, h = tile.size
  # obliczanie liczby potrzebnych kafelków
  cols = int(W/w) + 1
  rows = int(H/h) + 1
  # wklejanie kafelków do obrazu
  for i in range(rows):
    for j in range(cols):
      img.paste(tile, (j*w, i*h))
  # zwracanie obrazu
  return img

# tworzenie mapy głębi do testowania:
def createDepthMap(dims):
  dmap = Image.new('L', dims)
  dmap.paste(10, (200, 25, 300, 125))
  dmap.paste(30, (200, 150, 300, 250))
  dmap.paste(20, (200, 275, 300, 375))
  return dmap

# Dla danych mapy głębi (obrazu) i obrazu wejściowego tworzymy nowy obraz
# z pikselami przesuniętymi zgodnie z wartościami głębi
def createDepthShiftedImage(dmap, img):
  # sprawdzanie rozmiaru
  assert dmap.size == img.size
  # tworzenie przesuniętego obrazu
  sImg = img.copy()
  # uzyskanie dostępu do pikseli
  pixD = dmap.load()
  pixS = sImg.load()
  # przesuwanie pikseli dla wyjściowego obrazu na podstawie mapy głębi
  cols, rows = sImg.size
  for j in range(rows):
    for i in range(cols):
      xshift = pixD[i, j]/10
      xpos = i - 140 + xshift
      if xpos > 0 and xpos < cols:
        pixS[i, j] = pixS[xpos, j]
  # zwracanie przesuniętego obrazu
  return sImg

# Dla danych mapy głębi (obrazu) i obrazu wejściowego tworzymy nowy obraz
# z pikselami przesuniętymi zgodnie z wartościami głębi
def createAutostereogram(dmap, tile):
  # w razie potrzeby konwertowanie mapy głębi na pojedynczy kanał
  if dmap.mode is not 'L':
    dmap = dmap.convert('L')
  # jeśli nie został określony obraz dla kafelka, tworzymy kafelek z przypadkowymi kółeczkami
  if not tile:
    tile = createRandomTile((100, 100))
  # tworzenie obrazu przez składanie kafelków
  img = createTiledImage(tile, dmap.size)
  # tworzenie przesuniętego obrazu przy użyciu wartości mapy głębi
  sImg = img.copy()
  # uzyskiwanie dostępu do pikseli obrazu poprzez załadowanie najpierw obiektu Image
  pixD = dmap.load()
  pixS = sImg.load()
  # przesuwanie pikseli poziomo na podstawie mapy głębi
  cols, rows = sImg.size
  for j in range(rows):
    for i in range(cols):
      xshift = pixD[i, j]/10
      xpos = i - tile.size[0] + xshift
      if xpos > 0 and xpos < cols:
        pixS[i, j] = pixS[xpos, j]
  # zwracanie przesuniętego obrazu
  return sImg

# funkcja main()
def main():
  # w razie potrzeby użycie sys.argv
  print('tworzenie autostereogramu...')
  # tworzenie parsera
  parser = argparse.ArgumentParser(description="Autosterogramy...")
  # dodawanie oczekiwanych argumentów
  parser.add_argument('--depth', dest='dmFile', required=True)
  parser.add_argument('--tile', dest='tileFile', required=False)
  parser.add_argument('--out', dest='outFile', required=False)
  # parsowanie args
  args = parser.parse_args()
  # ustawianie pliku wyjściowego
  outFile = 'as.png'
  if args.outFile:
      outFile = args.outFile
  # ustawianie kafelka
  tileFile = False
  if args.tileFile:
      tileFile = Image.open(args.tileFile)
  # otwieranie mapy głębi
  dmImg = Image.open(args.dmFile)
  # tworzenie stereogramu
  asImg = createAutostereogram(dmImg, tileFile)
  # zapisywanie danych wyjściowych
  asImg.save(outFile)

# wywołanie main
if __name__ == '__main__':
  main()
