Esempio n. 1
0
    def cover_with(self, cover_color):
        """
        Mix the two colors respecting their alpha value.

        Puts cover_color over itself compositing the colors using the alpha
        values.
        """
        # fastpath for solid colors
        if cover_color.alpha == 255:
            return Color(cover_color.red, cover_color.green, cover_color.blue,
                         cover_color.alpha)

        srca = fdiv(cover_color.alpha, 255)
        dsta = fdiv(self.alpha, 255)
        outa = srca + dsta * (1 - srca)

        srcr, srcg, srcb = cover_color.red, cover_color.green, cover_color.blue
        dstr, dstg, dstb = self.red, self.green, self.blue

        outr = (srcr * srca + dstr * dsta * (1 - srca)) / outa
        outg = (srcg * srca + dstg * dsta * (1 - srca)) / outa
        outb = (srcb * srca + dstb * dsta * (1 - srca)) / outa

        red = int(round(outr))
        green = int(round(outg))
        blue = int(round(outb))
        alpha = int(round(outa * 255))

        return Color(red, green, blue, alpha)
Esempio n. 2
0
    def resize(self, source, width, height, resize_canvas=True):
        if not resize_canvas:
            # this optimised implementation doesn't deal with this.
            # so delegate to affine()
            return super(Nearest, self).resize(source,
                                               width,
                                               height,
                                               resize_canvas=resize_canvas)
        pixels = array.array('B')
        pixelsize = source.pixelsize

        x_ratio = fdiv(source.width, width)  # get the x-axis ratio
        y_ratio = fdiv(source.height, height)  # get the y-axis ratio

        y_range = range(
            height)  # an iterator over the indices of all lines (y-axis)
        x_range = range(
            width)  # an iterator over the indices of all rows (x-axis)
        for y in y_range:
            y += 0.5  # use the center of each pixel
            source_y = int(y * y_ratio)  # get the source line
            for x in x_range:
                x += 0.5  # use the center of each pixel
                source_x = int(x * x_ratio)  # get the source row
                pixels.extend(source.pixels.get(source_x, source_y))
        return get_pixel_array(pixels, width, height, pixelsize)
Esempio n. 3
0
    def cover_with(self, cover_color):
        """
        Mix the two colors respecting their alpha value.
        
        Puts cover_color over itself compositing the colors using the alpha
        values.
        """
        # fastpath for solid colors
        if cover_color.alpha == 255:
            return Color(cover_color.red, cover_color.green, cover_color.blue, cover_color.alpha)

        srca = fdiv(cover_color.alpha, 255)
        dsta = fdiv(self.alpha, 255)
        outa = srca + dsta * (1 - srca)

        srcr, srcg, srcb = cover_color.red, cover_color.green, cover_color.blue
        dstr, dstg, dstb = self.red, self.green, self.blue
        
        outr = (srcr * srca + dstr * dsta * (1 - srca)) / outa
        outg = (srcg * srca + dstg * dsta * (1 - srca)) / outa
        outb = (srcb * srca + dstb * dsta * (1 - srca)) / outa
        
        red = int(round(outr))
        green = int(round(outg))
        blue = int(round(outb))
        alpha = int(round(outa * 255))

        return Color(red, green, blue, alpha)
Esempio n. 4
0
    def __init__(self, start_x, start_y, end_x, end_y):
        self.start_x = start_x
        self.start_y = start_y
        self.end_x = end_x
        self.end_y = end_y
        steep = abs(self.end_y - self.start_y) > abs(self.end_x - self.start_x)
        if steep:
            x0, y0 = self.start_y, self.start_x
            x1, y1 = self.end_y, self.end_x
        else:
            x0, y0 = self.start_x, self.start_y
            x1, y1 = self.end_x, self.end_y
        if x0 > x1:
            x0, x1 = x1, x0
            y0, y1 = y1, y0

        self.x0, self.x1, self.y0, self.y1 = x0, x1, y0, y1

        delta_x = x1 - x0
        delta_y = abs(y1 - y0)
        self.error = 0.0
        self.delta_error = fdiv(delta_y, delta_x)
        if y0 < y1:
            self.ystep = 1
        else:
            self.ystep = -1

        self.y = y0

        self.iterator = self.steep_iterator if steep else self.normal_iterator
Esempio n. 5
0
 def __init__(self, start_x, start_y, end_x, end_y):
     self.start_x = start_x
     self.start_y = start_y
     self.end_x = end_x
     self.end_y = end_y
     steep = abs(self.end_y - self.start_y) > abs(self.end_x - self.start_x)
     if steep:
         x0, y0 = self.start_y, self.start_x
         x1, y1 = self.end_y, self.end_x
     else:
         x0, y0 = self.start_x, self.start_y
         x1, y1 = self.end_x, self.end_y
     if x0 > x1:
         x0, x1 = x1, x0
         y0, y1 = y1, y0
     
     self.x0, self.x1, self.y0, self.y1 = x0, x1, y0, y1
     
     delta_x = x1 - x0
     delta_y = abs(y1 - y0)
     self.error = 0.0
     self.delta_error = fdiv(delta_y, delta_x)
     if y0 < y1:
         self.ystep = 1
     else:
         self.ystep = -1
     
     self.y = y0
     
     self.iterator = self.steep_iterator if steep else self.normal_iterator
Esempio n. 6
0
    def cover_with(self, base):
        """
        Mix the two colors respecting their alpha value.
        """
        srca = fdiv(base.alpha, 255)
        dsta = fdiv(self.alpha, 255)
        outa = srca + dsta * (1 - srca)

        srcr, srcg, srcb = base.red, base.green, base.blue
        dstr, dstg, dstb = self.red, self.green, self.blue

        outr = (srcr * srca + dstr * dsta * (1 - srca)) / outa
        outg = (srcg * srca + dstg * dsta * (1 - srca)) / outa
        outb = (srcb * srca + dstb * dsta * (1 - srca)) / outa

        return Color(*map(int, [outr, outg, outb, outa * 255]))
Esempio n. 7
0
def nearest(source, width, height, pixelsize):
    assert pixelsize == 1, "yea... gotta implement this generically"
    pixels = []
    pixelappend = pixels.append # cache for cpython
    x_ratio = fdiv(source.width, width) # get the x-axis ratio
    y_ratio = fdiv(source.height, height) # get the y-axis ratio
    y_range = range(height) # an iterator over the indices of all lines (y-axis)
    x_range = range(width) # an iterator over the indices of all rows (x-axis)
    for y in y_range:
        source_y = int(round(y * y_ratio)) # get the source line
        line = array.array('B') # initialize a new line
        lineappend = line.append # cache for cypthon
        for x in x_range:
            source_x = int(round(x * x_ratio)) # get the source row
            lineappend(source.pixels[source_y][source_x])
        pixelappend(line)
    return pixels
Esempio n. 8
0
def nearest(source, width, height, pixelsize):
    pixels = []
    pixelappend = pixels.append # cache for cpython
    x_ratio = fdiv(source.width, width) # get the x-axis ratio
    y_ratio = fdiv(source.height, height) # get the y-axis ratio
    y_range = range(height) # an iterator over the indices of all lines (y-axis)
    x_range = range(width) # an iterator over the indices of all rows (x-axis)
    for y in y_range:
        source_y = int(round(y * y_ratio)) # get the source line
        line = array.array('B') # initialize a new line
        lineextend = line.extend # cache for cypthon
        for x_coord in x_range:
            source_x_coord = int(round(x_coord * x_ratio)) # get the source row
            source_x_start = source_x_coord * pixelsize
            source_x_end = source_x_start + pixelsize
            lineextend(source.pixels[source_y][source_x_start:source_x_end])
        pixelappend(line)
    return pixels
Esempio n. 9
0
 def iter_pixels(self, color):
     """
     Use Bresenham Line Algorithm (http://en.wikipedia.org/wiki/Bresenham's_line_algorithm):
     
     function line(x0, x1, y0, y1)
         boolean steep := abs(y1 - y0) > abs(x1 - x0)
         if steep then
             swap(x0, y0)
             swap(x1, y1)
         if x0 > x1 then
             swap(x0, x1)
             swap(y0, y1)
         int deltax := x1 - x0
         int deltay := abs(y1 - y0)
         real error := 0
         real deltaerr := deltay / deltax
         int ystep
         int y := y0
         if y0 < y1 then ystep := 1 else ystep := -1
         for x from x0 to x1
             if steep then plot(y,x) else plot(x,y)
             error := error + deltaerr
             if error ≥ 0.5 then
                 y := y + ystep
                 error := error - 1.0
     """
     steep = abs(self.end_y - self.start_y) > abs(self.end_x - self.start_x)
     if steep:
         x0, y0 = self.start_y, self.start_x
         x1, y1 = self.end_y, self.end_x
     else:
         x0, y0 = self.start_x, self.start_y
         x1, y1 = self.end_x, self.end_y
     if x0 > x1:
         x0, x1 = x1, x0
         y0, y1 = y1, y0
     
     delta_x = x1 - x0
     delta_y = abs(y1 - y0)
     error = 0.0
     delta_error = fdiv(delta_y, delta_x)
     if y0 < y1:
         ystep = 1
     else:
         ystep = -1
     
     y = y0
     
     for x in range(x0, x1):
         if steep:
             yield y, x, color
         else:
             yield x, y, color
         error += delta_error
         if error >= 0.5:
             y = y + ystep
             error = error - 1.0
Esempio n. 10
0
    def resize(self, source, width, height, resize_canvas=True):
        if not resize_canvas:
            # this optimised implementation doesn't deal with this.
            # so delegate to affine()
            return super(Nearest, self).resize(
                source, width, height, resize_canvas=resize_canvas
            )
        pixels = array.array('B')
        pixelsize = source.pixelsize

        x_ratio = fdiv(source.width, width)  # get the x-axis ratio
        y_ratio = fdiv(source.height, height)  # get the y-axis ratio

        y_range = range(height)  # an iterator over the indices of all lines (y-axis)
        x_range = range(width)  # an iterator over the indices of all rows (x-axis)
        for y in y_range:
            y += 0.5  # use the center of each pixel
            source_y = int(y * y_ratio)  # get the source line
            for x in x_range:
                x += 0.5  # use the center of each pixel
                source_x = int(x * x_ratio)  # get the source row
                pixels.extend(source.pixels.get(source_x, source_y))
        return get_pixel_array(pixels, width, height, pixelsize)
Esempio n. 11
0
 def init(self):
     if self.current_pass > self.LAST_PASS:
         self.done = True
         return
     self.xstart, self.ystart, self.xstep, self.ystep = self.passes[self.current_pass]
     self.pixels_per_row = int(math.ceil(fdiv(self.reader.width - self.xstart, self.xstep)))
     self.row_bytes = int(math.ceil(self.reader.psize * self.pixels_per_row))
     self.reader.scanline_length = self.get_scanline_length()
     if self.ystart >= self.reader.height:
         # empty pass
         self.next_pass()
     elif self.xstart >= self.reader.width:
         # empty pass
         self.next_pass()
     else:
         self.yiter = irange(self.ystart, self.reader.height, self.ystep)
         self.current_y = next(self.yiter)
Esempio n. 12
0
 def init(self):
     if self.current_pass > self.LAST_PASS:
         self.done = True
         return
     self.xstart, self.ystart, self.xstep, self.ystep = self.passes[
         self.current_pass]
     self.pixels_per_row = int(
         math.ceil(fdiv(self.reader.width - self.xstart, self.xstep)))
     self.row_bytes = int(
         math.ceil(self.reader.pixelsize * self.pixels_per_row))
     self.reader.scanline_length = self.get_scanline_length()
     if self.ystart >= self.reader.height:
         # empty pass
         self.next_pass()
     elif self.xstart >= self.reader.width:
         # empty pass
         self.next_pass()
     else:
         self.yiter = irange(self.ystart, self.reader.height, self.ystep)
         self.current_y = next(self.yiter)
Esempio n. 13
0
def _mixin_alpha(colors, alpha):
    from pymaging.utils import fdiv
    ratio = fdiv(alpha, 255)
    return [int(round(color *  ratio)) for color in colors]
Esempio n. 14
0
    def iter_pixels(self, color):
        """
        Use Xiaolin Wu's line algorithm: http://en.wikipedia.org/wiki/Xiaolin_Wu%27s_line_algorithm
        
        function plot(x, y, c) is
            plot the pixel at (x, y) with brightness c (where 0 ≤ c ≤ 1)
        
        function ipart(x) is
            return integer part of x
        
        function round(x) is
            return ipart(x + 0.5)
        
        function fpart(x) is
            return fractional part of x
        
        function rfpart(x) is
            return 1 - fpart(x)
        
        function drawLine(x1,y1,x2,y2) is
            dx = x2 - x1
            dy = y2 - y1
            if abs(dx) < abs(dy) then                 
              swap x1, y1
              swap x2, y2
              swap dx, dy
            end if
            if x2 < x1
              swap x1, x2
              swap y1, y2
            end if
            gradient = dy / dx
            
            // handle first endpoint
            xend = round(x1)
            yend = y1 + gradient * (xend - x1)
            xgap = rfpart(x1 + 0.5)
            xpxl1 = xend  // this will be used in the main loop
            ypxl1 = ipart(yend)
            plot(xpxl1, ypxl1, rfpart(yend) * xgap)
            plot(xpxl1, ypxl1 + 1, fpart(yend) * xgap)
            intery = yend + gradient // first y-intersection for the main loop
            
            // handle second endpoint
            xend = round (x2)
            yend = y2 + gradient * (xend - x2)
            xgap = fpart(x2 + 0.5)
            xpxl2 = xend  // this will be used in the main loop
            ypxl2 = ipart (yend)
            plot (xpxl2, ypxl2, rfpart (yend) * xgap)
            plot (xpxl2, ypxl2 + 1, fpart (yend) * xgap)
            
            // main loop
            for x from xpxl1 + 1 to xpxl2 - 1 do
                plot (x, ipart (intery), rfpart (intery))
                plot (x, ipart (intery) + 1, fpart (intery))
                intery = intery + gradient
        end function
        """
        def _plot(x, y, c):
            """
            plot the pixel at (x, y) with brightness c (where 0 ≤ c ≤ 1)
            """
            return int(x), int(y), color.get_for_brightness(c)

        dx = self.end_x - self.start_x
        dy = self.end_y - self.start_y
        x1, x2, y1, y2 = self.start_x, self.end_x, self.start_y, self.end_y
        if abs(dx) > abs(dy):
            x1, y1 = y1, x1
            x2, y2 = y2, x2
            dx, dy = dy, dx
        if x2 < x1:
            x1, x2 = x2, x1
            y1, y2 = y2, y1

        gradient = fdiv(dy, dx)

        xend = round(x1)
        yend = y1 + gradient * (xend - x1)
        xgap = _rfpart(x1 + 0.5)
        xpxl1 = xend
        ypxl1 = _ipart(yend)
        yield _plot(xpxl1, ypxl1, _rfpart(yend) * xgap)
        yield _plot(xpxl1, ypxl1 + 1, _fpart(yend) * xgap)

        intery = yend + gradient

        xend = _round(x2)
        yend = y2 + gradient * (xend - x2)
        xgap = _fpart(x2 + 0.5)
        xpxl2 = xend
        ypxl2 = _ipart(yend)
        yield _plot(xpxl2, ypxl2, _rfpart(yend) * xgap)
        yield _plot(xpxl2, ypxl2 + 1, _fpart(yend) * xgap)

        for x in range(xpxl1 + 1, xpxl2 - 1):
            yield _plot(x, _ipart(intery), _rfpart(intery))
            yield _plot(x, _ipart(intery) + 1, _fpart(intery))
            intery += gradient
Esempio n. 15
0
def _mixin_alpha(colors, alpha):
    ratio = fdiv(alpha, 255)
    return [int(round(color *  ratio)) for color in colors]
Esempio n. 16
0
def _mixin_alpha(colors, alpha):
    ratio = fdiv(alpha, 255)
    return [int(round(color * ratio)) for color in colors]
Esempio n. 17
0
    def handle_chunk_IHDR(self, chunk, length):
        # http://www.w3.org/TR/PNG/#11IHDR
        if length != 13:
            raise ChunkError('IHDR chunk has incorrect length %s, should be 13.' % length)
        (self.width, self.height, self.bit_depth, self.color_type,
         self.compression_method, self.filter_method,
         self.interlace_method) = struct.unpack("!2I5B", chunk)

        # Check that the header specifies only valid combinations.
        if self.bit_depth not in ALLOWED_BIT_DEPTHS:
            raise PNGReaderError("invalid bit depth %d" % self.bit_depth)
        
        if self.color_type not in ALLOWED_COLOR_TYPES:
            raise PNGReaderError("invalid colour type %d" % self.color_type)
        
        # Check indexed (palettized) images have 8 or fewer bits
        # per pixel; check only indexed or greyscale images have
        # fewer than 8 bits per pixel.
        if ((self.color_type & 1 and self.bit_depth > 8) or
            (self.bit_depth < 8 and self.color_type not in (0,3))):
            raise PNGReaderError("Illegal combination of bit depth (%d)"
              " and colour type (%d)."
              " See http://www.w3.org/TR/2003/REC-PNG-20031110/#table111 ."
              % (self.bit_depth, self.color_type))
        if self.compression_method != 0:
            raise PNGReaderError("unknown compression method %d" % self.compression_method)
        if self.filter_method != 0:
            raise PNGReaderError("Unknown filter method %d,"
              " see http://www.w3.org/TR/2003/REC-PNG-20031110/#9Filters ."
              % self.filter_method)
        if self.interlace_method not in (0, 1):
            raise PNGReaderError("Unknown interlace method %d,"
              " see http://www.w3.org/TR/2003/REC-PNG-20031110/#8InterlaceMethods ."
              % self.interlace_method)

        # Derived values
        # http://www.w3.org/TR/PNG/#6Colour-values
        colormap =  bool(self.color_type & 1)
        greyscale = not (self.color_type & 2)
        alpha = bool(self.color_type & 4)
        if greyscale or colormap:
            color_planes = 1
        else:
            color_planes = 3
        planes = color_planes + alpha

        self.colormap = colormap
        self.greyscale = greyscale
        self.alpha = alpha
        self.color_planes = color_planes
        self.planes = planes
        self.psize = fdiv(self.bit_depth, 8) * planes
        if int(self.psize) == self.psize:
            self.psize = int(self.psize)
        self.filter_unit = max(1, self.psize)
        self.row_bytes = int(math.ceil(self.width * self.psize))
        # scanline stuff
        self.scanline = array('B')
        if self.bit_depth == 16:
            array_code = 'H'
        else:
            array_code = 'B'
        if self.interlace_method:
            self.adam7 = Adam7(self)
            self.pixels = [array(array_code, [0] * self.width * self.psize) for _ in range(self.height)]
            self.scanline_length = self.adam7.get_scanline_length()
            self._process_scanline = self._process_interlaced_scanline
        else:
            self.previous_scanline = None
            self.pixels = []
            self.scanline_length = self.row_bytes + 1
            self._process_scanline = self._process_straightlaced_scanline
Esempio n. 18
0
    def handle_chunk_IHDR(self, chunk, length):
        # http://www.w3.org/TR/PNG/#11IHDR
        if length != 13:
            raise ChunkError(
                'IHDR chunk has incorrect length %s, should be 13.' % length)
        (self.width, self.height, self.bit_depth, self.color_type,
         self.compression_method, self.filter_method,
         self.interlace_method) = struct.unpack("!2I5B", chunk)

        # Check that the header specifies only valid combinations.
        if self.bit_depth not in ALLOWED_BIT_DEPTHS:
            raise PNGReaderError("invalid bit depth %d" % self.bit_depth)

        if self.color_type not in ALLOWED_COLOR_TYPES:
            raise PNGReaderError("invalid colour type %d" % self.color_type)

        # Check indexed (palettized) images have 8 or fewer bits
        # per pixel; check only indexed or greyscale images have
        # fewer than 8 bits per pixel.
        if ((self.color_type & 1 and self.bit_depth > 8)
                or (self.bit_depth < 8 and self.color_type not in (0, 3))):
            raise PNGReaderError(
                "Illegal combination of bit depth (%d)"
                " and colour type (%d)."
                " See http://www.w3.org/TR/2003/REC-PNG-20031110/#table111 ." %
                (self.bit_depth, self.color_type))
        if self.compression_method != 0:
            raise PNGReaderError("unknown compression method %d" %
                                 self.compression_method)
        if self.filter_method != 0:
            raise PNGReaderError(
                "Unknown filter method %d,"
                " see http://www.w3.org/TR/2003/REC-PNG-20031110/#9Filters ." %
                self.filter_method)
        if self.interlace_method not in (0, 1):
            raise PNGReaderError(
                "Unknown interlace method %d,"
                " see http://www.w3.org/TR/2003/REC-PNG-20031110/#8InterlaceMethods ."
                % self.interlace_method)

        self.pixelsize = {
            0: 1,
            2: 3,
            3: 1,
            4: 2,
            6: 4,
        }[self.color_type]

        # Derived values
        # http://www.w3.org/TR/PNG/#6Colour-values
        colormap = bool(self.color_type & 1)
        greyscale = not (self.color_type & 2)
        alpha = bool(self.color_type & 4)
        if greyscale or colormap:
            color_planes = 1
        else:
            color_planes = 3
        planes = color_planes + alpha

        self.colormap = colormap
        self.greyscale = greyscale
        self.alpha = alpha
        self.mode = RGBA if self.alpha else RGB
        self.color_planes = color_planes
        self.planes = planes
        self.psize = fdiv(self.bit_depth, 8) * planes
        if int(self.psize) == self.psize:
            self.psize = int(self.psize)
        self.filter_unit = max(1, self.psize)
        self.row_bytes = int(math.ceil(self.width * self.psize))
        # scanline stuff
        self.scanline = array.array('B')
        if self.bit_depth == 16:
            array_code = 'H'
        else:
            array_code = 'B'
        data = array.array(array_code,
                           [0] * self.width * self.height * self.pixelsize)
        self.pixels = get_pixel_array(data, self.width, self.height,
                                      self.pixelsize)
        if self.interlace_method:
            self.adam7 = Adam7(self)
            self.scanline_length = self.adam7.get_scanline_length()
            self._process_scanline = self._process_interlaced_scanline
        else:
            self.previous_scanline = None
            self.scanline_length = self.row_bytes + 1
            self.current_y = 0
            self._process_scanline = self._process_straightlaced_scanline
Esempio n. 19
0
    def resize(self, source, width, height, resize_canvas=True):
        if not resize_canvas:
            # this optimised implementation doesn't deal with this.
            # so delegate to affine()
            return super(Bilinear, self).resize(
                source, width, height, resize_canvas=resize_canvas
            )
        x_ratio = fdiv(source.width, width)  # get the x-axis ratio
        y_ratio = fdiv(source.height, height)  # get the y-axis ratio
        pixelsize = source.pixelsize
        pixels = array.array('B')

        if source.palette:
            raise NotImplementedError("Resampling of paletted images is not yet supported")

        if x_ratio < 1 and y_ratio < 1:
            if not (width % source.width) and not (height % source.height):
                # optimisation: if doing a perfect upscale,
                # can just use nearest neighbor (it's much faster)
                return nearest.resize(source, width, height)

        has_alpha = source.mode.alpha
        color_channels_range = range(pixelsize - 1 if has_alpha else pixelsize)

        y_range = range(height)  # an iterator over the indices of all lines (y-axis)
        x_range = range(width)  # an iterator over the indices of all rows (x-axis)
        for y in y_range:
            src_y = (y + 0.5) * y_ratio - 0.5  # use the center of each pixel
            src_y_i = int(src_y)

            weight_y0 = 1 - abs(src_y - src_y_i)

            for x in x_range:
                src_x = (x + 0.5) * x_ratio - 0.5
                src_x_i = int(src_x)

                weight_x0 = 1 - abs(src_x - src_x_i)

                channel_sums = [0.0] * pixelsize

                # populate <=4 nearest src_pixels, taking care not to go off
                # the edge of the image.
                src_pixels = [source.get_color(src_y_i, src_x_i), None, None, None]
                if src_x_i + 1 < source.width:
                    src_pixels[1] = source.get_color(src_y_i, src_x_i + 1)
                else:
                    weight_x0 = 1
                if src_y_i + 1 < source.height:
                    src_pixels[2] = source.get_color(src_y_i + 1, src_x_i)
                    if src_x_i + 1 < source.height:
                        src_pixels[3] = source.get_color(src_y_i + 1, src_x_i + 1)
                else:
                    weight_y0 = 1

                for i, src_pixel in enumerate(src_pixels):
                    if src_pixel is None:
                        continue
                    src_pixel = src_pixel.to_pixel(pixelsize)
                    weight_x = (1 - weight_x0) if (i % 2) else weight_x0
                    weight_y = (1 - weight_y0) if (i // 2) else weight_y0
                    alpha_weight = weight_x * weight_y
                    color_weight = alpha_weight
                    alpha = 255
                    if has_alpha:
                        alpha = src_pixel[-1]
                        if not alpha:
                            continue
                        color_weight *= (alpha / 255.0)
                    for channel_index, channel_value in zip(color_channels_range, src_pixel):
                        channel_sums[channel_index] += color_weight * channel_value

                    if has_alpha:
                        channel_sums[-1] += alpha_weight * alpha
                if has_alpha:
                    total_alpha_multiplier = channel_sums[-1] / 255.0
                    if total_alpha_multiplier:  # (avoid div/0)
                        for channel_index in color_channels_range:
                            channel_sums[channel_index] /= total_alpha_multiplier
                pixels.extend([int(round(s)) for s in channel_sums])
        return get_pixel_array(pixels, width, height, pixelsize)
Esempio n. 20
0
 def iter_pixels(self, color):
     """
     Use Xiaolin Wu's line algorithm: http://en.wikipedia.org/wiki/Xiaolin_Wu%27s_line_algorithm
     
     function plot(x, y, c) is
         plot the pixel at (x, y) with brightness c (where 0 ≤ c ≤ 1)
     
     function ipart(x) is
         return integer part of x
     
     function round(x) is
         return ipart(x + 0.5)
     
     function fpart(x) is
         return fractional part of x
     
     function rfpart(x) is
         return 1 - fpart(x)
     
     function drawLine(x1,y1,x2,y2) is
         dx = x2 - x1
         dy = y2 - y1
         if abs(dx) < abs(dy) then                 
           swap x1, y1
           swap x2, y2
           swap dx, dy
         end if
         if x2 < x1
           swap x1, x2
           swap y1, y2
         end if
         gradient = dy / dx
         
         // handle first endpoint
         xend = round(x1)
         yend = y1 + gradient * (xend - x1)
         xgap = rfpart(x1 + 0.5)
         xpxl1 = xend  // this will be used in the main loop
         ypxl1 = ipart(yend)
         plot(xpxl1, ypxl1, rfpart(yend) * xgap)
         plot(xpxl1, ypxl1 + 1, fpart(yend) * xgap)
         intery = yend + gradient // first y-intersection for the main loop
         
         // handle second endpoint
         xend = round (x2)
         yend = y2 + gradient * (xend - x2)
         xgap = fpart(x2 + 0.5)
         xpxl2 = xend  // this will be used in the main loop
         ypxl2 = ipart (yend)
         plot (xpxl2, ypxl2, rfpart (yend) * xgap)
         plot (xpxl2, ypxl2 + 1, fpart (yend) * xgap)
         
         // main loop
         for x from xpxl1 + 1 to xpxl2 - 1 do
             plot (x, ipart (intery), rfpart (intery))
             plot (x, ipart (intery) + 1, fpart (intery))
             intery = intery + gradient
     end function
     """
     def _plot(x, y, c):
         """
         plot the pixel at (x, y) with brightness c (where 0 ≤ c ≤ 1)
         """
         return int(x), int(y), color.get_for_brightness(c)
     dx = self.end_x - self.start_x
     dy = self.end_y - self.start_y
     x1, x2, y1, y2 = self.start_x, self.end_x, self.start_y, self.end_y
     if abs(dx) > abs(dy):
         x1, y1 = y1, x1
         x2, y2 = y2, x2
         dx, dy = dy, dx
     if x2 < x1:
         x1, x2 = x2, x1
         y1, y2 = y2, y1
     
     gradient = fdiv(dy, dx)
     
     xend = round(x1)
     yend = y1 + gradient * (xend - x1)
     xgap = _rfpart(x1 + 0.5)
     xpxl1 = xend 
     ypxl1 = _ipart(yend)
     yield _plot(xpxl1, ypxl1, _rfpart(yend) * xgap)
     yield _plot(xpxl1, ypxl1 + 1, _fpart(yend) * xgap)
     
     intery = yend + gradient
     
     xend = _round(x2)
     yend = y2 + gradient *  (xend - x2)
     xgap = _fpart(x2 + 0.5)
     xpxl2 = xend
     ypxl2 = _ipart(yend)
     yield _plot(xpxl2, ypxl2, _rfpart(yend) * xgap)
     yield _plot(xpxl2, ypxl2 + 1, _fpart(yend) * xgap)
     
     for x in range (xpxl1 + 1, xpxl2 - 1):
         yield _plot(x, _ipart(intery), _rfpart(intery))
         yield _plot(x, _ipart(intery) + 1, _fpart(intery))
         intery += gradient