import ctypes
from pythonmagickwand import api, wand, color


class Image(object):
    ''' Represents a single image, supported by a MagickWand.'''

    def __init__(self, image=None):
        self._wand = api.NewMagickWand()

        if hasattr(image, 'read'):
            c = image.read()
            self._check_wand_error(api.MagickReadImageBlob(self._wand, c, len(c)))
        elif image and isinstance(image, str):
            self._check_wand_error(api.MagickReadImage(self._wand, image))
	elif image and isinstance(image, ctypes.POINTER(api.MagickWand)):
	    self._wand=image

    def __del__(self):
        if self._wand:
            self._wand = api.DestroyMagickWand(self._wand)

    def _check_wand_error(self, func):
        wand._check_wand_error(self._wand, func)

    def _get_format(self):
        format = api.MagickGetImageFormat(self._wand)
        if format == '':
            return None
        else:
            return format

    def _set_format(self, value):
        self._check_wand_error(api.MagickSetImageFormat(self._wand, value))

    def _get_units(self):
        units = api.MagickGetImageUnits(self._wand)
        if units == api.UndefinedResolution:
            return None
        else:
            return units

    def _set_units(self, value):
        if value and value is wand.PIXELS_PER_INCH or value is wand.PIXELS_PER_CENTIMETER:
            self._check_wand_error(api.MagickSetImageUnits(self._wand, value))
        elif not value:
            self._check_wand_error(api.MagickSetImageUnits(self._wand, api.UndefinedResolution))
        else:
            raise ValueError('units must be one of None, PIXELS_PER_INCH or PIXELS_PER_CENTIMETER')

    def _get_resolution(self):
        x = y = ctypes.POINTER(ctypes.c_double)
	x = y = ctypes.c_double()
        self._check_wand_error(api.MagickGetImageResolution(self._wand, x, y))
        return (x.value, y.value)

    def _set_resolution(self, value):
        self._check_wand_error(api.MagickSetImageResolution(self._wand, value[0], value[1]))

    def _get_size(self):
        width = api.MagickGetImageWidth(self._wand)
        height = api.MagickGetImageHeight(self._wand)
        return (width, height)

    def _set_colorspace(self, colorspace):
        self._check_wand_error(api.MagickSetImageColorspace(self._wand, colorspace))

    def _get_colorspace(self):
        colorspace = api.MagickGetImageColorspace(self._wand)
        if colorspace == api.UndefinedColorspace:
            return None
        else:
            return colorspace

    def _get_background_color(self):
        c = color.TRANSPARENT
        self._check_wand_error(api.MagickGetImageBackgroundColor(self._wand, c._wand))
        return c

    def _set_background_color(self, color):
        self._check_wand_error(api.MagickSetImageBackgroundColor(self._wand, color._wand))

    def _get_border_color(self):
        c = color.TRANSPARENT
        self._check_wand_error(api.MagickGetImageBorderColor(self._wand, c._wand))
        return c

    def _set_border_color(self, color):
        self._check_wand_error(api.MagickSetImageBorderColor(self._wand, color._wand))
	


    def is_magick_wand(self):       # ??????
            self._check_wand_error(api.IsMagickWand(self._wand))

    def clear_exception(self):      # ????????
            self._check_wand_error(api.MagickClearException(self._wand))

    def reset_iterator(self):
            self._check_wand_error(api.MagickResetIterator(self._wand))

    def set_first_iterator(self):
            self._check_wand_error(api.MagickSetFirstIterator(self._wand))

    def set_last_iterator(self):
            self._check_wand_error(api.MagickSetLastIterator(self._wand))

 #   def clip_path(self, pathname, inside):
#            self._check_wand_error(api.MagickClipImagePath(self._wand, pathname, inside))

    def get_channel_statistics(self):
            channel_statistics=ctypes.POINTER(api.ChannelStatistics)()
            channel_statistics=api.MagickGetImageChannelStatistics(self._wand)
            return channel_statistics

    def get_filename(self):
            filename=api.MagickGetImageFilename(self._wand)
            if filename=='':
                return None
            else:
                return filename

    def get_signature(self):
            signature=api.MagickGetImageSignature(self._wand)
            if signature=='':
                return None
            else:
                return signature

    def identify(self):
            attributes=api.MagickIdentifyImage(self._wand)
            if attributes=='':
                return None
            else:
                return attributes

    def get_compose(self):
            return api.MagickGetImageCompose(self._wand)

    def get_dispose(self):
            return api.MagickGetImageDispose(self._wand)

    def get_gamma(self):
            gamma=ctypes.c_double()
            gamma=api.MagickGetImageGamma(self._wand)
            return gamma.value

    def get_total_ink_density(self):
            ink_density=ctypes.c_double()
            ink_density=api.MagickGetImageTotalInkDensity(self._wand)
            return ink_density.value

    def get_image_from_magick_wand(self):
            image=ctypes.POINTER(api.Image)()
            image=api.GetImageFromMagickWand(self._wand)
            return image

    def get_interlace_scheme(self):
            return api.MagickGetImageInterlaceScheme(self._wand)

    def get_property(self, property_):
            _property = api.MagickGetImageProperty(self._wand, property_)
            if _property == '':
                return None
            else:
                return _property

    def adaptive_threshold(self, width, height, offset):
            self._check_wand_error(api.MagickAdaptiveThresholdImage(self._wand, width, height, offset))

    def add_image(self, add_wand):
            self._check_wand_error(api.MagickAddImage(self._wand, add_wand))

    def affine_transform(self, drawing_wand):
            self._check_wand_error(api.MagickAffineTransformImage(self._wand, drawing_wand))

    def annotate(self, drawing_wand, x, y, angle, text):
            self._check_wand_error(api.MagickAnnotateImage(self._wand, drawing_wand, x, y, angle, text))

    def animate(self, server_name):
            self._check_wand_error(api.MagickAnimateImages(self._wand, server_name))

    def black_threshold(self, pixel_wand):
            self._check_wand_error(api.MagickBlackThresholdImage(self._wand, pixel_wand._wand))

    def charcoal(self, radius, sigma):
            self._check_wand_error(api.MagickCharcoalImage(self._wand, radius, sigma))

    def colorize(self, colorize, opacity):
            self._check_wand_error(api.MagickColorizeImage(self._wand, colorize._wand, opacity._wand))

    def comment(self, comment):
            self._check_wand_error(api.MagickCommentImage(self._wand, comment))

    def convolve(self, order, kernel, channel=None):
            ''' applies a custom convolution kernel to the image.
            channel:
                the image channel(s).

            order:
                the number of columns and rows in the filter kernel.

            kernel:
                An tuple of doubles representing the convolution kernel.'''
            
            array = ctypes.c_double * (order**2)
            kernel = array(*kernel)
            if channel:
                self._check_wand_error(api.MagickConvolveImageChannel(self._wand, channel, order, kernel))
            else:
                self._check_wand_error(api.MagickConvolveImage(self._wand, order, kernel))

    def cycle_colormap(self, displace):
            self._check_wand_error(api.MagickCycleColormapImage(self._wand, displace))

    def display(self, server_name):
            self._check_wand_error(api.MagickDisplayImage(self._wand, server_name))

    def display_images(self, server_name):
            self._check_wand_error(api.MagickDisplayImages(self._wand, server_name))

    def draw(self, drawing_wand):
            self._check_wand_error(api.MagickDrawImage(self._wand, drawing_wand._wand))

    def emboss(self, radius, sigma):
            self._check_wand_error(api.MagickEmbossImage(self._wand, radius, sigma))

    def frame(self, matte_color, width, height, inner_bevel, outer_bevel):
            self._check_wand_error(api.MagickFrameImage(self._wand, matte_color._wand, width, height, inner_bevel, outer_bevel))

    def get_red_primary(self):
            x = y = ctypes.POINTER(ctypes.c_double)
	    x = y = ctypes.c_double()
            self._check_wand_error(api.MagickGetImageRedPrimary(self._wand, x, y))
            return x.value, y.value

    def get_green_primary(self):
            x = y = ctypes.POINTER(ctypes.c_double)
	    x = y = ctypes.c_double()
            self._check_wand_error(api.MagickGetImageGreenPrimary(self._wand, x, y))
            return x.value, y.value

    def get_blue_primary(self):
            x = y = ctypes.POINTER(ctypes.c_double)
	    x = y = ctypes.c_double()
            self._check_wand_error(api.MagickGetImageBluePrimary(self._wand, x, y))
            return x.value, y.value

    def get_distortion(self, reference, metric, channel=None):
            distortion = ctypes.POINTER(ctypes.c_double)
	    distortion = ctypes.c_double()
            if channel:
                self._check_wand_error(api.MagickGetImageChannelDistortion(self._wand, reference._wand, channel, metric, distortion))
            else:
                self._check_wand_error(api.MagickGetImageDistortion(self._wand, reference._wand, metric, distortion))

            return distortion.value

    def get_channel_mean(self, channel):
            mean = std_dev = ctypes.POINTER(ctypes.c_double)
	    mean = std_dev = ctypes.c_double()
            self._check_wand_error(api.MagickGetImageChannelMean(self._wand, channel, mean, std_dev))
            return mean.value, std_dev.value

    def get_colormap_color(self, index):
            c=color.TRANSPARENT
            self._check_wand_error(api.MagickGetImageColormapColor(self._wand, index, c._wand))
            return c

    def get_matte_color(self):
            c=color.TRANSPARENT
            self._check_wand_error(api.MagickGetImageMatteColor(self._wand, c._wand))
            return c

    def get_page(self):
            width = height = ctypes.POINTER(ctypes.c_ulong)
	    width = height=ctypes.c_ulong()
	    x_offset = y_offset = ctypes.POINTER(ctypes.c_long)
	    x_offset = y_offset =ctypes.c_long()
            self._check_wand_error(api.MagickGetImagePage(self._wand, width, height, x_offset, y_offset))
            return (width.value, height.value), (x_offset.value, y_offset.value)

    def get_white_point(self):
            x = y = ctypes.POINTER(ctypes.c_double)
	    x = y= ctypes.c_double()
            self._check_wand_error(api.MagickGetImageWhitePoint(self._wand, x, y))
            return x.value, y.value

    def get_orientation(self):
            _dict = {0:'UndefinedOrientation', 1:'TopLeftOrientation', 2:'TopRightOrientation', 3:'BottomRightOrientation',\
            4:'BottomLeftOrientation', 5:'LeftTopOrientation', 6:'RightTopOrientation', 7:'RightBottomOrientation',\
            8:'LeftBottomOrientation'}
            orientation = api.MagickGetImageOrientation(self._wand)
            return _dict[orientation]

    def has_next_image(self):
            return api.MagickHasNextImage(self._wand)

    def has_previous_image(self):
            return api.MagickHasPreviousImage(self._wand)

    def label(self, label):
            self._check_wand_error(api.MagickLabelImage(self._wand, label))

    def _map(self, map_wand, dither):
            self._check_wand_error(api.MagickMapImage(self._wand, map_wand._wand, dither))

    def negate(self, gray, channel=None):
            if channel:
                self._check_wand_error(api.MagickNegateImageChannel(self._wand, channel, gray))
            else:
                self._check_wand_error(api.MagickNegateImage(self._wand, gray))

    def new_image(self, width, height, color):
            self._check_wand_error(api.MagickNewImage(self._wand, width, height, color._wand))

    def oil_paint(self, radius):
            self._check_wand_error(api.MagickOilPaintImage(self._wand, radius))

    def posterize(self, levels, dither):
            self._check_wand_error(api.MagickPosterizeImage(self._wand, levels, dither))

    def previous_image(self):
            self._check_wand_error(api.MagickPreviousImage(self._wand))

    def raise_image(self, width, height, x, y, _raise):
            self._check_wand_error(api.MagickRaiseImage(self._wand, width, height, x, y, _raise))

    def remove_image(self):
            self._check_wand_error(api.MagickRemoveImage(self._wand))

    def roll(self, x_offset, y_offset):
            self._check_wand_error(api.MagickRollImage(self._wand, x_offset, y_offset))

    def sample(self, width, height):
            self._check_wand_error(api.MagickSampleImage(self._wand, width, height))

    def separate_channel(self, channel):
            self._check_wand_error(api.MagickSeparateImageChannel(self._wand, channel))

    def set_image(self, set_wand):
            self._check_wand_error(api.MagickSetImage(self._wand, set_wand._wand))

    def set_bias(self, bias):
            self._check_wand_error(api.MagickSetImageBias(self._wand, bias))

    def set_blue_primary(self, coordinates):
            self._check_wand_error(api.MagickSetImageBluePrimary(self._wand, coordinates[0], coordinates[1]))

    def set_green_primary(self, coordinates):
            self._check_wand_error(api.MagickSetImageGreenPrimary(self._wand, coordinates[0], coordinates[1]))

    def set_red_primary(self, coordinates):
            self._check_wand_error(api.MagickSetImageRedPrimary(self._wand, coordinates[0], coordinates[1]))

    def set_colormap_color(self, index, color):
            self._check_wand_error(api.MagickSetImageColormapColor(self._wand, index, color._wand))

    def set_compose(self, CompositeOp):
            self._check_wand_error(api.MagickSetImageCompose(self._wand, CompositeOp))#############

    def set_delay(self, delay):
            self._check_wand_error(api.MagickSetImageDelay(self._wand, delay))

    def set_dispose(self, DisposeType):
            self._check_wand_error(api.MagickSetImageDispose(self._wand, DisposeType))#################

    def set_gamma(self, gamma):
            self._check_wand_error(api.MagickSetImageGamma(self._wand, gamma))

    def set_extent(self, width, height):
            self._check_wand_error(api.MagickSetImageExtent(self._wand, width, height))

    def set_filename(self, filename):
            self._check_wand_error(api.MagickSetImageFilename(self._wand, filename))

    def set_interlace_scheme(self, InterlaceType):
            '''InterlaceType:
                    One of the following strings: UndefinedInterlace, NoInterlace, LineInterlace, PlaneInterlace,\
                    PartitionInterlace, GIFInterlace, JPGInterlace, PNGInterlace.'''
            _dict = {'UndefinedInterlace':api.UndefinedInterlace, 'NoInterlace':api.NoInterlace, 'LineInterlace':api.LineInterlace,\
            'PlaneInterlace':api.PlaneInterlace, 'PartitionInterlace':api.PartitionInterlace, 'GIFInterlace':api.GIFInterlace,\
            'JPGInterlace':api.JPGInterlace, 'PNGInterlace':api.PNGInterlace}
            self._check_wand_error(api.MagickSetImageInterlaceScheme(self._wand, _dict[InterlaceType]))

    def set_iterations(self, iterations):
            self._check_wand_error(api.MagickSetImageIterations(self._wand, iterations))

    def set_matte_color(self, matte):
            self._check_wand_error(api.MagickSetImageMatteColor(self._wand, matte._wand))

    def set_pixels(self, x, y, width, height, _map, pixels):
	    ''' pixels is a tuple of float type values normalized [0..1]'''
            array = ctypes.c_double * len(pixels)
            pixels = array(*pixels)
            self._check_wand_error(api.MagickSetImagePixels(self._wand, x, y, width, height, _map, api.DoublePixel, pixels))

    def set_rendering_intent(self, RenderingIntent):
            '''RenderingIntent:
                        One of the following string: SaturationIntent, PerceptualIntent, AbsoluteIntent, RelativeIntent.'''
            _dict = {'SaturationIntent' : api.SaturationIntent, 'PerceptualIntent' : api.PerceptualIntent,\
            'AbsoluteIntent' : api.AbsoluteIntent, 'RelativeIntent' : api.RelativeIntent}
            self._check_wand_error(api.MagickSetImageRenderingIntent(self._wand, _dict[RenderingIntent]))

    def set_scene(self, scene_number):
            self._check_wand_error(api.MagickSetImageScene(self._wand, scene_number))

    def set_ticks_per_second(self, ticks_per_second):
            self._check_wand_error(api.MagickSetImageTicksPerSecond(self._wand, ticks_per_second))

    def set_type(self, ImageType):
            '''ImageType:
                    One of the following strings: Bilevel, Grayscale, GrayscaleMatte, Palette, PaletteMatte,
                    TrueColor, TrueColorMatte, ColorSeparation, ColorSeparationMatte.'''
            _dict = {'Bilevel':1, 'Grayscale':2, 'GrayscaleMatte':3, 'Palette':4, 'PaletteMatte':5, 'TrueColor':6,\
            'TrueColorMatte':7, 'ColorSeparation':8, 'ColorSeparationMatte':9}
            self._check_wand_error(api.MagickSetImageType(self._wand, ImageType))

    def set_white_point(self, coordinates):
            self._check_wand_error(api.MagickSetImageWhitePoint(self._wand, coordinates[0], coordinates[1]))

    def shadow(self, opacity, sigma, x, y):
            self._check_wand_error(api.MagickShadowImage(self._wand, opacity, sigma, x, y))

    def shave(self, width, height):
            self._check_wand_error(api.MagickShaveImage(self._wand, width, height))

    def sheare(self, background, x_shear, y_shear):
            self._check_wand_error(api.MagickShearImage(self._wand, background._wand, x_shear, y_shear))

    def solarize(self, threshold):
            self._check_wand_error(api.MagickSolarizeImage(self._wand, threshold))

    def spread(self, radius):
            self._check_wand_error(api.MagickSpreadImage(self._wand, radius))

    def strip(self):
            self._check_wand_error(api.MagickStripImage(self._wand))

    def swirl(self, degrees):
            self._check_wand_error(api.MagickSwirlImage(self._wand, degrees))

    def tint(self, tint, opacity):
            self._check_wand_error(api.MagickTintImage(self._wand, tint._wand, opacity._wand))

    def threshold(self, threshold, channel=None):
            if channel:
                self._check_wand_error(api.MagickThresholdImageChannel(self._wand, channel, threshold))
            else:
                self._check_wand_error(api.MagickThresholdImage(self._wand, threshold))

    def thumbnail(self, width, height):
            self._check_wand_error(api.MagickThumbnailImage(self._wand, width, height))

    def trim(self, fuzz):
            self._check_wand_error(api.MagickTrimImage(self._wand, fuzz))

    def wave(self, amplitude, wave_lenght):
            self._check_wand_error(api.MagickWaveImage(self._wand, amplitude, wave_lenght))

    def get_type(self):
            ''' gets the potential image type:'''
            
            _dict = {1:'Bilevel', 2:'Grayscale', 3:'GrayscaleMatte', 4:'Palette', 5:'PaletteMatte', 6:'TrueColor',\
            7:'TrueColorMatte', 8:'ColorSeparation', 9:'ColorSeparationMatte'}
	    image_type = api.MagickGetImageType(self._wand)
	    return _dict[image_type]
    
    def recolor(self, order, matrix):
            ''' translate, scale, shear, or rotate image colors.
            Although you can use variable sized matrices, typically you use a 5 x 5 for an RGBA image and a 6x6 for CMYKA.
            Populate the last row with normalized values to translate.
            A description of each parameter follows:

            order:
                the number of columns and rows in the color matrix.

            matrix:
                An tuple of doubles representing the color matrix.'''
            
	    array = ctypes.c_double * (order**2)
	    matrix = array(*matrix)
	    self._check_wand_error(api.MagickRecolorImage(self._wand, order, matrix))
	    
    def clone_magick_wand(self):
            ''' makes an exact copy of the specified wand.'''
	    newwand = ctypes.POINTER(api.MagickWand)()
	    newwand = api.CloneMagickWand(self._wand)
	    return newwand
    
    def get_image(self):
            '''  gets the image at the current image index.'''
	    newwand = ctypes.POINTER(api.MagickWand)()
	    newwand = api.MagickGetImage(self._wand)
	    return newwand

    def get_region(self, size, offset):
            ''' Extracts a region of the image and returns it as a new wand.

            size - A tuple describing the size of the image region.
            offset - A tuple describing the region offset.'''
            newwand = ctypes.POINTER(api.MagickWand)()
            newwand = api.MagickGetImageRegion(self._wand, size[0], size[1], offset[0], offset[1])
            return newwand

    def fx(self, expression):
            ''' evaluates expression for each pixel in the image.'''
	    newwand = ctypes.POINTER(api.MagickWand)()
	    newwand = api.MagickFxImage(self._wand,expression)
	    return newwand
    
    def set_page(self, size, offset):
	    ''' sets the page geometry of the image.'''
	    self._check_wand_error(api.MagickSetImagePage(self._wand, size[0], size[1], offset[0], offset[1]))	

    def get_pixels(self, x, y, columns, rows, _map, pixels):
	    '''Returns an iterable ctypes array object. It is a flatten array of double type values normalized [0..1].
	    
	    wand:
		the magick wand.
		
	    x, y, columns, rows:
	    
		These values define the perimeter of a region of pixels you want to extract.
	    _map:

                This string reflects the expected ordering of the pixel array. 
		It can be any combination or order of R = red, G = green, B = blue, A = alpha (0 is transparent), 
		O = opacity (0 is opaque), C = cyan, Y = yellow, M = magenta, K = black, I = intensity (for grayscale), P = pad.'''
    #        pixels = (ctypes.c_double * (columns * rows * len(_map)))() 
	    self._check_wand_error(api.MagickGetImagePixels(self._wand, long(x), long(y), columns, rows,\
            _map, api.CharPixel, pixels.ctypes.data_as(ctypes.c_void_p)))
	    return pixels
	    
	
    def border(self, color, width, height):
            '''surraunds an image with a color defined by color.Color(color_str).The specified color_str can be a name or string
            representation of a color.  Acceptable values can be found in the
            ImageMagick documentation at
            http://www.imagemagick.org/script/color.php.    '''

            self._check_wand_error(api.MagickBorderImage(self._wand, color._wand, width, height))
	
    def sepia_tone(self, threshold):
	    '''applies a special effect to the image, similar to the effect achieved in a photo darkroom by sepia toning. 
	    Threshold ranges from 0 to QuantumRange and is a measure of the extent of the sepia toning. 
	    A threshold of 80 is a good starting point for a reasonable tone. '''

	    self._check_wand_error(api.MagickSepiaToneImage(self._wand, threshold))
	    
    def get_channel_depth(self, channel):
	    '''gets the depth for one or more image channels.'''
	    depth = api.MagickGetImageChannelDepth(self._wand, channel)
	    return depth
	    
    def get_depth(self):
	    '''gets the depth for one  image.'''
	    depth = api.MagickGetImageDepth(self._wand)
	    return depth
	    
    def reduce_noise(self, radius):
	    '''smooths the contours of an image while still preserving edge information. 
	    The algorithm works by replacing each pixel with its neighbor closest in value. 
	    A neighbor is defined by radius. Use a radius of 0 and ReduceNoise() selects a suitable radius for you.'''

	    self._check_wand_error(api.MagickReduceNoiseImage(self._wand, radius))
	    
    def add_noise(self, noise_type):
	    '''adds random noise to the image.
	    noise_type: 1=UniformNoise, 2=GaussianNoise, 3=MultiplicativeNoise, 4=ImpulseNoise, 5=LaplacianNoise, 6=PoissonNoise.'''

	    self._check_wand_error(api.MagickAddNoiseImage(self._wand, noise_type))

    def contrast_stretch(self, black_point, white_point):
            '''enhances the contrast of a color image by adjusting the pixels color
            to span the entire range of colors available. '''

            self._check_wand_error(api.MagickContrastStretchImage(self._wand, black_point, white_point))
	    
    def sigmoidal_contrast(self, sharpen, contrast, mid_point):
	    '''adjusts the contrast of an image with a non-linear sigmoidal contrast algorithm. 
	    Increase the contrast of the image using a sigmoidal transfer function without saturating highlights or shadows. 
	    Contrast indicates how much to increase the contrast (0 is none; 3 is typical; 20 is pushing it); 
	    mid_point indicates where midtones fall in the resultant image (0 is white; 50 is middle-gray; 100 is black). 
	    Set sharpen to True to increase the image contrast otherwise setting it to False the contrast is reduced. '''

	    self._check_wand_error(api.MagickSigmoidalContrastImage(self._wand, sharpen, contrast, mid_point))
	    
    def median_filter(self, radius):
	    ''' applies a digital filter that improves the quality of a noisy image. 
	    Each pixel is replaced by the median in a set of neighboring pixels as defined by radius.'''

	    self._check_wand_error(api.MagickMedianFilterImage(self._wand, radius))
	    
    def evaluate(self, EvaluateOperator, value, channel=None):
	    ''' applys an arithmetic, relational, or logical expression to an image. 
	    Use these operators to lighten or darken an image, to increase or decrease contrast in an image, 
	    or to produce the "negative" of an image.
	    EvaluateOperator:
                    One of the following strings: Add, And, Divide, LeftShift, Max, Min, Multiply, Or, RightShift, Set,\
                    Subtract, Xor. '''
	    _dict = {'Add':api.AddEvaluateOperator, 'And':api.AndEvaluateOperator, 'Divide':api.DivideEvaluateOperator,\
            'LeftShift':api.LeftShiftEvaluateOperator, 'Max':api.MaxEvaluateOperator, 'Min':api.MinEvaluateOperator,\
            'Multiply':api.MultiplyEvaluateOperator, 'Or':api.OrEvaluateOperator, 'RightShift':api.RightShiftEvaluateOperator,\
            'Set':api.SetEvaluateOperator, 'Subtract':api.SubtractEvaluateOperator, 'Xor':api.XorEvaluateOperator}

	    if channel:
		    self._check_wand_error(api.MagickEvaluateImageChannel(self._wand, channel, _dict[EvaluateOperator], value))
	    else:
		    self._check_wand_error(api.MagickEvaluateImage(self._wand, _dict[EvaluateOperator], value))

    def unsharp_mask(self, radius, sigma, amount, threshold):
            ''' sharpens an image. We convolve the image with a Gaussian operator of the given radius and standard deviation (sigma). For reasonable results, radius should be larger than sigma. Use a radius of 0 and UnsharpMaskImage() selects a suitable radius for you.

            radius:
                    the radius of the Gaussian, in pixels, not counting the center pixel.

            sigma:
                    the standard deviation of the Gaussian, in pixels.

            amount:
                    the percentage of the difference between the original and the blur image that is added back into the original.

            threshold:
                    the threshold in pixels needed to apply the diffence amount.'''

            self._check_wand_error(api.MagickUnsharpMaskImage(self._wand, radius, sigma, amount, threshold))

    def set_depth(self, depth, channel=None):
            '''Sets the image depth. depth is a long constant'''
            if not channel:
                self._check_wand_error(api.MagickSetImageDepth(self._wand, depth))
            else:
                self._check_wand_error(api.MagickSetImageChannelDepth(self._wand, channel, depth))
		    
    def white_threshold(self, threshold):
            self._check_wand_error(api.MagickWhiteThresholdImage(self._wand, threshold._wand))

    def write_file(self, file_descriptor):
            self._check_wand_error(api.MagickWriteImageFile(self._wand, file_descriptor))

    def write_images(self, filename, adjoin):
            self._check_wand_error(api.MagickWriteImages(self._wand, filename, adjoin))

    def write_images_file(self, file_descriptor):
            self._check_wand_error(api.MagickWriteImagesFile(self._wand, file_descriptor))

    def opaque_paint(self, target, fill, fuzz):
            self._check_wand_error(api.MagickPaintOpaqueImage(self._wand, target._wand, fill._wand, fuzz))
	        

	    
        
    def _get_compression(self):
        compression = api.MagickGetImageCompression(self._wand)
        if compression == wand.NO_COMPRESSION:
            return None
        else:
            return compression

    def _set_compression(self, compression):
        if not compression:
            compression = wand.NO_COMPRESSION
        self._check_wand_error(api.MagickSetImageCompression(self._wand, compression))

    def _get_compression_quality(self):
        return api.MagickGetImageCompressionQuality(self._wand)

    def _set_compression_quality(self, quality):
        self._check_wand_error(api.MagickSetImageCompressionQuality(self._wand, int(round(quality, 0))))

    def save(self, file=None):
        ''' Saves the image to a file.  If no file is specified, the file is
            saved with the original filename.'''

        if hasattr(file, 'write'):
            size = api.size_t()
            b = api.MagickGetImageBlob(self._wand, size)
            try:
                file.write(''.join([chr(b[i]) for i in range(0, size.value + 1)]))
            finally:
                api.MagickRelinquishMemory(b)
        else:
            self._check_wand_error(api.MagickWriteImage(self._wand, file))

    def scale(self, width, height):
        ''' Scales the size of image to the given dimensions.'''
        
        self._check_wand_error(api.MagickScaleImage(self._wand,width, height))

    def resize(self, size, filter=None, blur=0):
        ''' Resize the image with the given filter and applying some blur.

            size - A tuple containing the size of the scaled image.
            filter - None, or one of BESSEL_FILTER, BLACKMAN_FILTER,
                     BOX_FILTER, CATROM_FILTER, CUBIC_FILTER, GAUSSIAN_FILTER,
                     HANNING_FILTER, HERMITE_FILTER, LANCZOS_FILTER,
                     MITCHELL_FILTER, POINT_FILTER, QUADRATIC_FILTER,
                     SINC_FILTER, or TRIANGLE_FILTER.
             blur - blur factor where > 1 is blurry, < 1 is sharp.  Default is
                    no blur.'''

        if not filter:
            filter = api.UndefinedFilter

        self._check_wand_error(api.MagickResizeImage(self._wand, size[0], size[1], filter, blur))

    def resample(self, resolution, filter=None, blur=0):
        ''' Resample the image with the given filter and applying some blur.

            size - A tuple containing the resolution of the resampled image.
            filter - None, or one of BESSEL_FILTER, BLACKMAN_FILTER,
                     BOX_FILTER, CATROM_FILTER, CUBIC_FILTER, GAUSSIAN_FILTER,
                     HANNING_FILTER, HERMITE_FILTER, LANCZOS_FILTER,
                     MITCHELL_FILTER, POINT_FILTER, QUADRATIC_FILTER,
                     SINC_FILTER, or TRIANGLE_FILTER.
             blur - blur factor where > 1 is blurry, < 1 is sharp.  Default is
                    no blur.'''

        if not filter:
            filter = api.UndefinedFilter

        self._check_wand_error(api.MagickResampleImage(self._wand, resolution[0], resolution[1], filter, blur))

    def sharpen(self, radius, sigma, channel=None):
        ''' Sharpen the image with a Gaussian operator of the given radius and
            standard deviation.  For best results, the radius should be larger
            than sigma.  If radius is 0, a suitable radius is automatically
            selected.  If channel is provided, the sharpen is restricted to
            that particular channel.

            radius - The radius of the Gaussian operator, in pixels, not
                     counting the center pixel.
            sigma - The standard deviation of the Gaussian operator, in pixels.
            channel - None, or one of RED_CHANNEL, CYAN_CHANNEL, GREEN_CHANNEL,
                      MAGENTA_CHANNEL, BLUE_CHANNEL, YELLOW_CHANNEL,
                      ALPHA_CHANNEL, OPACITY_CHANNEL, BLACK_CHANNEL,
                      INDEX_CHANNEL, ALL_CHANNELS.'''

        if channel:
            self._check_wand_error(api.MagickSharpenImageChannel(self._wand, channel, radius, sigma))
        else:
            self._check_wand_error(api.MagickSharpenImage(self._wand, radius, sigma))

    def blur(self, radius, sigma, operator=None):
        ''' Blurs the image with a Gaussian operator of the given radius and
            standard deviation.  For best results, the radius should be larger
            than sigma.  If radius is 0, a suitable radius is automatically
            selected.  If channel is provided, the blur is restricted to
            that particular channel.

            radius - The radius of the Gaussian operator, in pixels, not
                     counting the center pixel.
            sigma - The standard deviation of the Gaussian operator, in pixels.
            channel - None, or one of RED_CHANNEL, CYAN_CHANNEL, GREEN_CHANNEL,
                      MAGENTA_CHANNEL, BLUE_CHANNEL, YELLOW_CHANNEL,
                      ALPHA_CHANNEL, OPACITY_CHANNEL, BLACK_CHANNEL,
                      INDEX_CHANNEL, ALL_CHANNELS.'''

        if operator:
            self._check_wand_error(api.MagickGaussianBlurImage(self._wand, radius, sigma))
        else:
            self._check_wand_error(api.MagickBlurImage(self._wand, radius, sigma))

    def motion_blur(self, radius, sigma, angle):
        ''' Simulates motion blur in an image by convolving the image with a
            Gaussian operator of the given radius and standard deviation.  For best
            results, the radius should be larger than sigma.  If radius is 0, a
            suitable radius is automatically selected.

            radius - The radius of the Gaussian operator, in pixels, not
                     counting the center pixel.
            sigma - The standard deviation of the Gaussian operator, in pixels.
            angle - Apply the effect along this angle.'''

        self._check_wand_error(api.MagickMotionBlurImage(self._wand, radius, sigma, angle))

    def despeckle(self):
        ''' Reduces the speckle noise in the image.'''
        self._check_wand_error(api.MagickDespeckleImage(self._wand))

    def edge(self, radius=0):
        ''' Enhances the edges within the image, using a convolution filter of
            the given radius.  If no radius is given, a suitable one is
            automatically chosen.
            
            radius = The radius of the pixel neighborhood.'''

        self._check_wand_error(api.MagickEdgeImage(self._wand, radius))

    def enhance(self):
        ''' Applies a digital filter which improves the quality of a noisy image.'''
        self._check_wand_error(api.MagickEnhanceImage(self._wand))

    def median_filter(self, radius):
        ''' Applies a digital filter that improves the quality of a noisy
            image. Each pixel is replaced by the median in a set of neighboring
            pixels as defined by radius.

            radius - The radius of the pixel neighborhood.'''

        self._check_wand_error(api.MagickMedianFilterImage(self._wand, radius))

    def equalize(self):
        ''' Equalizes the histogram of the image.'''
        self._check_wand_error(api.MagickEqualizeImage(self._wand))

    def clip(self):
        ''' Clips along the first path from the 8BIM profile, if present.'''
        self._check_wand_error(api.MagickClipImage(self._wand))

    def chop(self, size, offset):
        ''' Remove a region of the image and collapse the image to occupy the
            removed portion.

            size - A tuple describing the size of the image region.
            offset - A tuple describing the region offset.'''

        self._check_wand_error(api.MagickChopImage(self._wand, size[0], size[1], offset[0], offset[1]))

    def splice(self, size, offset):
        ''' Splice a solid colour region into the image.  This can be reversed
            by a chop.

            size - A tuple describing the size of the image region.
            offset - A tuple describing the region offset.'''

        self._check_wand_error(api.MagickSpliceImage(self._wand, size[0], size[1], offset[0], offset[1]))

    def crop(self, size, offset):
        ''' Extract a region of the image.

            size - A tuple describing the size of the image region.
            offset - A tuple describing the region offset.'''

        self._check_wand_error(api.MagickCropImage(self._wand, size[0], size[1], offset[0], offset[1]))

    def flip(self):
        ''' Creates a vertical mirror image by reflecting the pixels around the
            central x-axis.'''
        self._check_wand_error(api.MagickFlipImage(self._wand))

    def flop(self):
        ''' Creates a horizontal mirror image by reflecting the pixels around
            the central y-axis.'''
        self._check_wand_error(api.MagickFlopImage(self._wand))

    def magnify(self):
        ''' Scales the image proportionally to twice its original size.'''
        self._check_wand_error(api.MagickMagnifyImage(self._wand))

    def minify(self):
        ''' Scales the image proportionally to one-half its original size.'''
        self._check_wand_error(api.MagickMinifyImage(self._wand))

    def rotate(self, degrees, background=None):
        ''' Rotate the image.

            degrees - The number of degrees to rotate the image.
            background - The Color to use for the empty area.  Default is the
                         image's background colour, if specified, or
                         transparent if not specified.'''

        if not background:
            try:
                background = self.background_color
            except:
                background = color.TRANSPARENT

            if not background:
                background = color.TRANSPARENT

        self._check_wand_error(api.MagickRotateImage(self._wand, background._wand, degrees))

    def normalize(self):
        ''' Enhances the contrast of a color image by adjusting the pixels
            color to span the entire range of colors available.'''
        self._check_wand_error(api.MagickNormalizeImage(self._wand))

    def modulate(self, brightness, saturation, hue):
        ''' Lets you control the brightness, saturation, and hue of an image.
            Hue is the percentage of absolute rotation from the current position.
            For example 50 results in a counter-clockwise rotation of 90 degrees,
            150 results in a clockwise rotation of 90 degrees, with 0 and 200 both
            resulting in a rotation of 180 degrees.

            brightness - The percent change in brightness.
            saturation - The percent change in saturation.
            hue - The percent change in hue.'''
        self._check_wand_error(api.MagickModulateImage(self._wand, brightness, saturation, hue))

    def adjust_levels(self, black_point, gamma, white_point, channel=None):
        ''' Adjust the image levels by scaling the colors falling between
            specified white and black points to the full available quantum range.
            The parameters provided represent the black, mid, and white points.
            Colors darker than the black point are set to zero.  Colors
            brighter than the white point are set to the maximum quantum value.
            If a channel is given, the level adjustment is restricted to the
            specified channel.

            black_point - The darkest color in the image.
            gamma - The gamma correction to apply to the image.
            white_point - The lightest color in the image.
            channel - None, or one of RED_CHANNEL, CYAN_CHANNEL, GREEN_CHANNEL,
                      MAGENTA_CHANNEL, BLUE_CHANNEL, YELLOW_CHANNEL,
                      ALPHA_CHANNEL, OPACITY_CHANNEL, BLACK_CHANNEL,
                      INDEX_CHANNEL, ALL_CHANNELS.'''

        if channel:
            self._check_wand_error(api.MagickLevelImageChannel(self._wand, channel, black_point, gamma, white_point))
        else:
            self._check_wand_error(api.MagickLevelImage(self._wand, black_point, gamma, white_point))

    def increase_contrast(self):
        ''' Increase the differences between lighter and darker elements of the image.'''
        self._check_wand_error(api.MagickContrastImage(self._wand, 1))
        
    def decrease_contrast(self):
        ''' Decrease the differences between lighter and darker elements of the image.'''
        self._check_wand_error(api.MagickContrastImage(self._wand, 0))

    def gamma_correct(self, gamma, channel=None):
        ''' Gamma correct an image.  If channel is provided, the gamma
            correction is restricted to that particular channel.  

            gamma - The level of gamma correction, typically in the range of
                    0.8 to 2.3.  If a value of 0 is given and a channel is
                    specified, the influence of that channel is reduced.
            channel - None, or one of RED_CHANNEL, CYAN_CHANNEL, GREEN_CHANNEL,
                      MAGENTA_CHANNEL, BLUE_CHANNEL, YELLOW_CHANNEL,
                      ALPHA_CHANNEL, OPACITY_CHANNEL, BLACK_CHANNEL,
                      INDEX_CHANNEL, ALL_CHANNELS.'''

        if channel:
            self._check_wand_error(api.MagickGammaImageChannel(self._wand, channel, gamma))
        else:
            self._check_wand_error(api.MagickGammaImage(self._wand, gamma))

    def composite(self, image, offset, operator=None, channel=None):
        ''' Composite another image on top of this one.

            image - The Image to composite onto this one.
            offset - A tuple describing the offset of the composited image.

            operator - This operator affects how the composite is applied to
                       the image. The default is OVER_COMPOSITE_OP. Choose from
                       these operators:

                            MINUS_COMPOSITE_OP
                            ADD_COMPOSITE_OP
                            IN_COMPOSITE_OP
                            DIFFERENCE_COMPOSITE_OP
                            PLUS_COMPOSITE_OP
                            BUMPMAP_COMPOSITE_OP
                            ATOP_COMPOSITE_OP
                            XOR_COMPOSITE_OP
                            SUBTRACT_COMPOSITE_OP
                            OUT_COMPOSITE_OP
                            COPY_COMPOSITE_OP
                            DISPLACE_COMPOSITE_OP
                            OVER_COMPOSITE_OP

            channel - None, or one of RED_CHANNEL, CYAN_CHANNEL, GREEN_CHANNEL,
                      MAGENTA_CHANNEL, BLUE_CHANNEL, YELLOW_CHANNEL,
                      ALPHA_CHANNEL, OPACITY_CHANNEL, BLACK_CHANNEL,
                      INDEX_CHANNEL, ALL_CHANNELS.'''

        if not operator:
            operator = wand.OVER_COMPOSITE_OP

        if channel:
            self._check_wand_error(api.MagickCompositeImageChannel(self._wand, channel, image._wand, operator, offset[0], offset[1]))
        else:
            self._check_wand_error(api.MagickCompositeImage(self._wand, image._wand, operator, offset[0], offset[1]))

    def quantize(self, colors, colorspace=None, tree_depth=1, dither=False, measure_error=False):
        ''' Limit the colours present in an image to a fixed amount.

            colors - The number of colors in the new image.
            colorspace - Perform color reduction in this colorspace, defaults to the image's colorspace.
            tree_depth - Default is to choose an optimal tree depth of
                         Log4(colors).  A tree of this depth generally allows
                         the best representation of the reference image with
                         the least amount of memory and the fastest
                         computational speed. In some cases, such as an image
                         with low color dispersion (a few number of colors), a
                         value other than Log4(number_colors) is required. To
                         expand the color tree completely, use a value of 8.
            dither - If True, the image is dithered.  Defaults to False.
            measure_error - If True, measures the difference between the
                            original and quantized images as an error.
                            Defaults to False.'''

        if not colorspace:
            colorspace = self.colorspace

        self._check_wand_error(api.MagickQuantizeImage(self._wand, colors, colorspace, tree_depth, dither, measure_error))

    format = property(_get_format, _set_format, None, 'The image format as a string, eg. "PNG".')
    units = property(_get_units, _set_units, None, 'The units of resolution for this image, ie. None, PIXELS_PER_INCH, PIXELS_PER_CENTIMETER.')
    resolution = property(_get_resolution, _set_resolution, None, 'A tuple containing the image resolution as expressed in image_units.')
    size = property(_get_size, scale, None, 'A tuple containing the size of the image. Setting the size is the same as calling scale().')
    colorspace = property(_get_colorspace, _set_colorspace, None, 'The image colorspace.')
    background_color = property(_get_background_color, _set_background_color, None, 'The background color of the image.')
    border_color = property(_get_border_color, _set_border_color, None, 'The border color of the image.')
    compression = property(_get_compression, _set_compression, None, 
        'The image compression to use, ie. None, BZIP_COMPRESSION,\
        FAX_COMPRESSION, GROUP4_COMPRESSION, JPEG_COMPRESSION,\
        LOSSLESS_JPEG_COMPRESSION, LZW_COMPRESSION, RLE_COMPRESSION and\
        ZIP_COMPRESSION')
    compression_quality = property(_get_compression_quality, _set_compression_quality, None, 'The compression quality of the image, as a percent.')
