# Image solid color checker by Clement
# optimizations by Nathan 'jesterKing' Letwory

import System
import os
import time
from System.Threading import Tasks as task


def IsImageAllSameColor(image_path, color):
    """Read image from path, then test each pixel against the 
    passed in color. Color is a list of color components
    with order [r, g, b, a]
    """

    if not os.path.exists(image_path): return
    
    # unpack the color, since we don't want to waste time on
    # lookups
    r, g, b, a = color
    
    # set up bitmap reading into array
    bmp = System.Drawing.Bitmap.FromFile(image_path)
    form = System.Drawing.Imaging.PixelFormat.Format32bppArgb
    mode = System.Drawing.Imaging.ImageLockMode.ReadOnly
    area = System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height)
    # and lock the data for specific format so we can copy for consumption
    data = bmp.LockBits(area, mode, form)
    
    # copy the image data to rgb_values array, so we can throw the bitmap away
    byte_count = (data.Stride) * data.Height
    rgb_values = System.Array.CreateInstance(System.Byte, byte_count)
    System.Runtime.InteropServices.Marshal.Copy(data.Scan0, rgb_values, 0, byte_count)
    # done with original bmp, unlock and release file handle
    bmp.UnlockBits(data)
    bmp.Dispose()
    
    # create a single-item list, so we can actually set it
    # it appears that using just same_color = True, then set
    # it in the worker doesn't work as expected. The list works
    # since it is really a reference, not a hard-copy of the value
    same_color = [True]
    
    # our worker takes an item from the input in i, one element
    # created by the xrange. The state we use to break the loop
    # as soon as we find a dissimilar color from what we want
    def Worker(i, state, unused):
        # we now test against the r,g,b,a variables in that order. Assuming
        # that alpha channel isn't what we're looking for we can put it last
        # so that any of r,g,b short-circuit. At best the r value is different
        # resulting in skipping of tests for g,b,and a. Worst case is only alpha
        # is different.
        # Also we no longer use any data structure to compare against to get rid
        # of any lookups
        if rgb_values[i+2] != r or rgb_values[i+1] != g or rgb_values[i] != b or rgb_values[i+3] != a:
            same_color[0] = False
            state.Break()
    
    # do the work
    task.Parallel.ForEach(xrange(0, byte_count, 4), Worker)
    
    return same_color[0]

def DoSomethingNew():
    image_path = r"N:/solidcolor_tester.png"
    
    test_color = [255,201,14,255] # r, g, b, a

    start = time.time()
    result = IsImageAllSameColor(image_path, test_color)
    end = time.time()
    
    return result, end-start

r = DoSomethingNew()
print r
#for i in range(5):
#    r = DoSomethingNew()
#    print r