Ejemplo n.º 1
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)
Ejemplo n.º 2
0
def _channels_data_to_image(channels_data, mode, size, depth):

    if size == (0, 0):
        return

    w, h = size
    num_channels = mode.length
    assert depth == 8
    assert len(channels_data) == num_channels

    total_size = w * h * num_channels
    image_bytes = array.array(str("B"), [0] * total_size)

    for index, channel in enumerate(channels_data):

        # zip and zip-with-prediction data is already decoded
        data = channel.data
        if channel.compression == Compression.PACK_BITS:
            data = packbits.decode(data)

        image_bytes[index::num_channels] = array.array(str("B"), data)

    pixels = get_pixel_array(image_bytes, w, h, mode.length)

    return LoadedImage(mode, w, h, pixels)
Ejemplo n.º 3
0
def pixel_array_factory(colors, alpha=True):
    height = len(colors)
    width = len(colors[0]) if height else 0
    pixel_size = 4 if alpha else 3
    pixel_array = get_pixel_array(array.array('i', [0] * width * height * pixel_size), width, height, pixel_size)
    for y in range(height):
        for x in range(width):
            pixel_array.set(x, y, colors[y][x].to_pixel(pixel_size))
    return pixel_array
Ejemplo n.º 4
0
def pixel_array_factory(colors, alpha=True):
    height = len(colors)
    width = len(colors[0]) if height else 0
    pixel_size = 4 if alpha else 3
    pixel_array = get_pixel_array(array.array('B', [0] * width * height * pixel_size), width, height, pixel_size)
    for y in range(height):
        for x in range(width):
            pixel_array.set(x, y, colors[y][x].to_pixel(pixel_size))
    return pixel_array
Ejemplo n.º 5
0
    def get_image(self):
        # go to the start of the pixel array
        self.fileobj.seek(self.offset)
        # since bmps are stored upside down, initialize a pixel list
        initial = array.array("B", [0] * self.width * self.height * self.pixelsize)
        pixel_array = get_pixel_array(initial, self.width, self.height, self.pixelsize)
        # iterate BACKWARDS over the line indices so we don't have to reverse
        # later. this is why we intialize pixels above.
        for row_num in range(self.height - 1, -1, -1):
            self.read_row(pixel_array, row_num)
        # TODO: Not necessarily RGB

        return Image(pixel_array, RGB, palette=self.palette)
Ejemplo n.º 6
0
 def new(cls,
         mode,
         width,
         height,
         background_color,
         palette=None,
         meta=None):
     color = background_color.to_pixel(mode.length)
     pixel_array = get_pixel_array(
         array.array('B', color) * width * height, width, height,
         mode.length)
     return LoadedImage(mode,
                        width,
                        height,
                        pixel_array,
                        palette=palette,
                        meta=meta)
Ejemplo n.º 7
0
def decode(fileobj):
    decoder = TonyJpegDecoder()
    jpegsrc = fileobj.read()
    try:
        bmpout = decoder.decode(jpegsrc)
    except:
        fileobj.seek(0)
        return None
    pixels = array.array('B')
    row_width = decoder.Width * PIXELSIZE
    # rows are bottom to top
    for reversed_row_num in range(decoder.Height - 1, -1, -1):
        start = reversed_row_num * (row_width + 2)
        end = start + row_width
        pixels.extend(bmpout[start:end])
        #pixels.extend(bmpout[:3 * decoder.Width])
        #del bmpout[:3 * decoder.Width]
        #del bmpout[:2] # kill padding
    pixel_array = get_pixel_array(pixels, decoder.Width, decoder.Height, PIXELSIZE)
    return Image(pixel_array, RGB)
Ejemplo n.º 8
0
def read_pixels(fileobj, headers):
    fileobj.seek(headers.palette_start)
    palette = []
    for _ in range(headers.ncolors):
        blue, green, red, _ = struct.unpack('<BBBB', fileobj.read(4))
        palette.append((red, green, blue))
    # set palette to None instead of empty list when there's no palette
    palette = palette or None

    read_row = ROW_READERS[headers.bits_per_pixel]

    fileobj.seek(headers.offset)
    # since bmps are stored upside down, initialize a pixel list
    initial = array.array('B', [0] * headers.width * headers.height * headers.pixelsize)
    pixel_array = get_pixel_array(initial, headers.width, headers.height, headers.pixelsize)
    # iterate BACKWARDS over the line indices so we don't have to reverse
    # later. this is why we intialize pixels above.
    for row_num in range(headers.height - 1, -1, -1):
        read_row(fileobj, headers, pixel_array, row_num)

    return pixel_array, palette
Ejemplo n.º 9
0
def decode(fileobj):
    decoder = TonyJpegDecoder()
    jpegsrc = fileobj.read()
    try:
        bmpout = decoder.decode(jpegsrc)
    except:
        fileobj.seek(0)
        return None
    pixels = array.array('B')
    row_width = decoder.Width * PIXELSIZE
    # rows are bottom to top
    for reversed_row_num in range(decoder.Height - 1, -1, -1):
        start = reversed_row_num * (row_width + 2)
        end = start + row_width
        pixels.extend(bmpout[start:end])
        #pixels.extend(bmpout[:3 * decoder.Width])
        #del bmpout[:3 * decoder.Width]
        #del bmpout[:2] # kill padding
    pixel_array = get_pixel_array(pixels, decoder.Width, decoder.Height,
                                  PIXELSIZE)
    return Image(pixel_array, RGB)
Ejemplo 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)
Ejemplo n.º 11
0
def _channels_data_to_image(channels_data, mode, size, depth):

    if size == (0, 0):
        return

    num_channels = mode.length
    assert depth == 8
    assert len(channels_data) == num_channels

    total_size = size[0]*size[1]*num_channels
    image_bytes = array.array(str("B"), [0]*total_size)

    for index, channel in enumerate(channels_data):

        data = channel.data # zip and zip-with-prediction data is already decoded
        if channel.compression == Compression.PACK_BITS:
            data = packbits.decode(data)

        image_bytes[index::num_channels] = array.array(str("B"), data)

    pixels = get_pixel_array(image_bytes, size[0], size[1], mode.length)

    return Image(pixels, mode)
Ejemplo n.º 12
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)
Ejemplo n.º 13
0
 def new(cls, mode, width, height, background_color, palette=None, meta=None):
     color = background_color.to_pixel(mode.length)
     pixel_array = get_pixel_array(array.array("B", color) * width * height, width, height, mode.length)
     return LoadedImage(mode, width, height, pixel_array, palette=palette, meta=meta)
Ejemplo n.º 14
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
Ejemplo n.º 15
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.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
Ejemplo n.º 16
0
 def new(cls, width, height, background_color, mode, palette=None):
     color = background_color.to_pixel(mode.length)
     pixel_array = get_pixel_array(array.array('B', color * width * height), width, height, mode.length)
     return Image(pixel_array, mode, palette=palette)