# Image manipulation API

from flask import Flask, render_template, send_from_directory, redirect
import os
from PIL import Image

app = Flask(__name__)

APP_ROOT = os.path.dirname(os.path.abspath(__file__))


# default access redirects to API documentation
@app.route("/")
def main():
    return render_template('index.html')


# rotate filename the specified degrees
@app.route("/rotate/<angle>/<filename>", methods=["GET"])
def rotate(angle, filename):

    # check for valid angle
    angle = int(angle)
    if not -360 < angle < 360:
        return render_template("error.html", message="Invalid angle parameter (-359 to 359)"), 400

    # open and process image
    target = os.path.join(APP_ROOT, 'static/images')
    destination = "/".join([target, filename])

    img = Image.open(destination)
    img = img.rotate(-1*angle)

    # save and return image
    destination = "/".join([target, 'temp.png'])
    if os.path.isfile(destination):
        os.remove(destination)
    img.save(destination)

    return send_image('temp.png')


# flip filename 'vertical' or 'horizontal'
@app.route("/flip/<mode>/<filename>", methods=["GET"])
def flip(mode, filename):

    # open and process image
    target = os.path.join(APP_ROOT, 'static/images')
    destination = "/".join([target, filename])

    img = Image.open(destination)

    # check mode
    if mode == 'horizontal':
        img = img.transpose(Image.FLIP_LEFT_RIGHT)
    elif mode == 'vertical':
        img = img.transpose(Image.FLIP_TOP_BOTTOM)
    else:
        return render_template("error.html", message="Invalid mode (vertical or horizontal)"), 400

    # save and return image
    destination = "/".join([target, 'temp.png'])
    if os.path.isfile(destination):
        os.remove(destination)
    img.save(destination)

    return send_image('temp.png')


# crop filename from (x1,y1) to (x2,y2)
@app.route("/crop/<x1>/<y1>/<x2>/<y2>/<filename>", methods=["GET"])
def crop(x1, y1, x2, y2, filename):

    # open image
    target = os.path.join(APP_ROOT, 'static/images')
    destination = "/".join([target, filename])

    img = Image.open(destination)
    width = img.size[0]
    height = img.size[1]

    # check for valid crop parameters
    [x1, y1, x2, y2] = [int(x1), int(y1), int(x2), int(y2)]

    crop_possible = True
    
    while True:
        if not 0 <= x1 < width:
            crop_possible = False
            break
        if not 0 < x2 <= width:
            crop_possible = False
            break
        if not 0 <= y1 < height:
            crop_possible = False
            break
        if not 0 < y2 <= height:
            crop_possible = False
            break
        if not x1 < x2:
            crop_possible = False
            break
        if not y1 < y2:
            crop_possible = False
            break
        break

    # process image
    if crop_possible:
        img = img.crop((x1, y1, x2, y2))
    else:
        return render_template("error.html", message="Crop dimensions not valid"), 400

    # save and return image
    destination = "/".join([target, 'temp.png'])
    if os.path.isfile(destination):
        os.remove(destination)
    img.save(destination)

    return send_image('temp.png')


# blend filename1 and filename2 with alpha parameter
@app.route("/blend/<alpha>/<filename1>/<filename2>", methods=["GET"])
def blend(alpha, filename1, filename2):

    # check for valid alpha
    alpha = float(alpha)
    if not 0 <= alpha <= 100:
        return render_template("error.html", message="Invalid alpha value (0-100)"), 400

    #open images
    target = os.path.join(APP_ROOT, 'static/images')
    destination1 = "/".join([target, filename1])
    destination2 = "/".join([target, filename2])

    img1 = Image.open(destination1)
    img2 = Image.open(destination2)

    # check for dimensions and resize to larger ones
    width = max(img1.size[0], img2.size[0])
    height = max(img1.size[1], img2.size[1])

    img1 = img1.resize((width, height), Image.ANTIALIAS)
    img2 = img2.resize((width, height), Image.ANTIALIAS)

    # if one image in gray scale, convert the other to monochrome
    if len(img1.mode) < 3:
        img2 = img2.convert('L')
    elif len(img2.mode) < 3:
        img1 = img1.convert('L')

    # blend images
    img = Image.blend(img1, img2, float(alpha)/100)

    # save and return
    destination = "/".join([target, 'temp.png'])
    if os.path.isfile(destination):
        os.remove(destination)
    img.save(destination)

    return send_image('temp.png')

#resize
@app.route("/resize/<width>/<length>/<filename>", methods=["GET"])
def resize(width, length, filename):

    # open image
    target = os.path.join(APP_ROOT, 'static/images')
    destination = "/".join([target, filename])

    img = Image.open(destination)
    #width = img.size[0]
    #length = img.size[1]

    # check for valid resize parameters
    [width, length]= [int(width), int(length)]

    # process image
    #if resize_possible:
    img = img.resize((width, length))
    #else:
    #    return render_template("error.html", message="Resize dimensions not valid"), 400

    # save and return image
    destination = "/".join([target, 'temp.png'])
    if os.path.isfile(destination):
        os.remove(destination)
    img.save(destination)

    return send_image('temp.png')

# Colourtransform filename 'grayscale' or 'rgbinvert'
@app.route("/transform/<mode>/<filename>", methods=["GET"])
def transform(mode, filename):

    # open and process image
    target = os.path.join(APP_ROOT, 'static/images')
    destination = "/".join([target, filename])

    img = Image.open(destination)

    # check mode
    if mode == 'grayscale':
        img = img.convert('L')
    elif mode == 'rgbinvert':
        img = Image.merge('RGB', (b,g,r))
    else:
        return render_template("error.html", message="Invalid mode (grayscale or rgbinvert)"), 400

    # save and return image
    destination = "/".join([target, 'temp.png'])
    if os.path.isfile(destination):
        os.remove(destination)
    img.save(destination)

    return send_image('temp.png')

#filters
@app.route("/filters/<mode>/<filename>", methods=["GET"])
def filters(mode, filename):

     # open and process image
    target = os.path.join(APP_ROOT, 'static/images')
    destination = "/".join([target, filename])

    img = Image.open(destination)

     # check mode
    if mode == 'blur':
        img = img.filter(ImageFilter.BLUR)
    elif mode == 'emboss':
        img = img.filter(ImageFilter.EMBOSS)
    elif mode == 'contour':
        img = img.filter(ImageFilter.CONTOUR)
    elif mode == 'findedges':
        img = img.filter(ImageFilter.FIND_EDGES)
    elif mode == 'smooth':
        img = img.filter(ImageFilter.SMOOTH_MORE)
    elif mode == 'sharpen':
        img = img.filter(ImageFilter.SHARPEN)
    else:
        return render_template("error.html", message="Invalid mode (grayscale or rgbinvert)"), 400

    # save and return image
    destination = "/".join([target, 'temp.png'])
    if os.path.isfile(destination):
        os.remove(destination)
    img.save(destination)

    return send_image('temp.png')

#enhance
@app.route("/enhance/<brightness>/<contrast>/<filename>", methods=["GET"])
def enhance(brightness, contrast, filenmae):
    # open image
    target = os.path.join(APP_ROOT, 'static/images')
    destination = "/".join([target, filename])

    img = Image.open(destination)

    # check for valid resize parameters
    [brightness, contrast]= [int(brightness, contrast)]

    #process image
    img = ImageEnhance.Brightness(img).enhance((brightness))
    img = ImageEnhance.Contrast(img).enhance((contrast))

    # save and return image
    destination = "/".join([target, 'temp.png'])
    if os.path.isfile(destination):
        os.remove(destination)
    img.save(destination)

    return send_image('temp.png')


# retrieve file from 'static/images' directory
@app.route('/static/images/<filename>')
def send_image(filename):
    return send_from_directory("static/images", filename)


if __name__ == "__main__":
    app.debug=True
    app.run()

