#!/usr/bin/env python

#
# Author: Maksym Pyatnytskyy
# Version: 0.2
#
# Implementation of Subtractive Chromatic Noise Reduction (SCNR) from PixInsight.
# 	http://www.pixinsight.com/doc/legacy/LE/21_noise_reduction/scnr/scnr.html
#
# General structure of the script is based on "python_fu_test_discolour_layer_v2" sample script by Jose F. Maldonado.
#

from gimpfu import *

def mp_astro_killing_green(img, layer, mode, maskAmount):

    # Indicates that the process has started.
    progressMessage = "Killing Green " + layer.name + "." + " Mode = " + str(mode)
    if mode == 0 or mode == 1:
        progressMessage += "; Amount = " + str(maskAmount)
    gimp.progress_init(progressMessage)

    # Set up an undo group, so the operation will be undone in one step.
    pdb.gimp_image_undo_group_start(img)

    # Get the layer position.
    pos = 0;
    for i in range(len(img.layers)):
        if(img.layers[i] == layer):
            pos = i
    
    # Create a new layer to save the results (otherwise is not possible to undo the operation).
    newLayer = gimp.Layer(img, layer.name + " temp", layer.width, layer.height, layer.type, layer.opacity, layer.mode)
    img.add_layer(newLayer, pos)
    layerName = layer.name
    
    # Clear the new layer.
    pdb.gimp_edit_clear(newLayer)
    newLayer.flush()

    # Iterate over all the pixels...
    try:

        if(len(layer.get_pixel(0, 0)) < 3):
            raise ValueError('Not an RGB* image')

        maxPixelComponentValue = 255.
        
		#test_max_val = 0
	
        for x in range(layer.width):
            # Update the progress bar.
            gimp.progress_update(float(x) / float(layer.width))

            for y in range(layer.height):
                # Get the pixel and verify that is an RGB value.
                pixel = layer.get_pixel(x, y)
				
                #test_max_val = max(test_max_val, pixel[0], pixel[1], pixel[2])
				
                gNew = pixel[1]
                if mode == 0:
                    # Maximum Mask Protection
                    # m = max(R, B)
                    # G' = G * (1 - a) * (1 - m) + m * G
                    m = max(pixel[0], pixel[2]) / maxPixelComponentValue
                    gNew = int(pixel[1] * (1.0 - maskAmount) * (1.0 - m) + m * pixel[1])
                elif mode == 1:
                    #Additive Mask Protection
                    # m = min(1, R + B)
                    # G' = G * (1 - a) * (1 - m) + m * G (same as Maximum Mask)
                    m = min(maxPixelComponentValue, pixel[0] + pixel[2]) / maxPixelComponentValue
                    gNew = int(pixel[1] * (1.0 - maskAmount) * (1.0 - m) + m * pixel[1])
                elif mode == 2:
                    # Average Neutral Protection
                    # m = 0.5 * (R + B)
                    # G' = min(G, m)
                    m = 0.5 * (pixel[0] + pixel[2])
                    gNew = int(min(pixel[1], m))
                elif mode == 3:
                    # Maximum Neutral Protection
                    # m = max(R, B) (same as Maximum Mask)
                    # G' = min(G, m) (same as Average Neutral)
                    m = max(pixel[0], pixel[2])
                    gNew = int(min(pixel[1], m))
                else:
                    raise ValueError('Mode is not implemented')

                newColor = (pixel[0], gNew, pixel[2]) + pixel[3:]
                newLayer.set_pixel(x, y, newColor)

        # Update the new layer.
        newLayer.flush()
        newLayer.merge_shadow(True)
        newLayer.update(0, 0, newLayer.width, newLayer.height)
        
        # Remove the old layer.
        img.remove_layer(layer)
        
        # Change the name of the new layer (two layers can not have the same name).
        newLayer.name = layerName

    except Exception as err:
        gimp.message("Unexpected error: " + str(err))

    # Close the undo group.
    pdb.gimp_image_undo_group_end(img)

    # End progress.
    pdb.gimp_progress_end()

    #pdb.gimp_message("test_max_val = " + str(test_max_val))
	
register(
    "python_fu_astro_killing_green",
    "Killing Green (SCNR)",
    "Uses very simple SCRN algorithm (from PixInsight) to reduce greenish noise",
    "Max Pyatnytskyy",
    "Max Pyatnytskyy",
    "2016",
    "<Image>/Filters/M.P. Astro/Killing green (SCNR)...",
    "RGB*",
    [
        (PF_RADIO, "mode", "Mode:", 2, (("Maximum Mask *", 0), ("Additive Mask *", 1), ("Average Neutral", 2), ("Additive Neutral", 3))),
		(PF_SLIDER, "maskAmount", "* Amount (Masked modes only)", 0.7, (0, 1, 0.01)),
    ],
    [],
    mp_astro_killing_green)

main()