Ejemplo n.º 1
0
    def createBitmap(self):
        minimum_color_depth = 1
        while self.numColors > 2**minimum_color_depth:
            minimum_color_depth *= 2

        file = open(self.path, mode="rb")
        bitmap = displayio.Bitmap(self.width, self.height, self.numColors)
        file.seek(self.dataOffset)
        line_size = self.width // (8 // self.colorPlanes)
        if self.width % (8 // self.colorPlanes) != 0:
            line_size += 1
        if line_size % 4 != 0:
            line_size += 4 - line_size % 4
        mask = (1 << self.colorPlanes) - 1
        if self.height > 0:
            range1 = self.height - 1
            range2 = -1
            range3 = -1
        else:
            range1 = 0
            range2 = abs(self.height)
            range3 = 1
        if self.compressionMethod == 0:
            if _bitmap_readinto:
                try:
                    _bitmap_readinto(bitmap,
                                     file,
                                     bits_per_pixel=self.colorPlanes,
                                     element_size=4,
                                     reverse_pixels_in_element=True,
                                     reverse_rows=True)
                except Exception as e:
                    print(repr(e))
            else:  # use the standard file.readinto
                chunk = bytearray(line_size)
                for y in range(range1, range2, range3):
                    file.readinto(chunk)
                    pixels_per_byte = 8 // self.colorPlanes
                    offset = y * self.width
                    for x in range(self.width):
                        i = x // pixels_per_byte
                        pixel = (chunk[i] >>
                                 (8 - color_depth *
                                  (x % pixels_per_byte + 1))) & mask
                        bitmap[offset + x] = pixel
        elif compression in (1, 2):
            decode_rle(
                bitmap=bitmap,
                file=file,
                compression=self.compressionMethod,
                y_range=(range1, range2, range3),
                width=self.width,
            )
        return bitmap
Ejemplo n.º 2
0
def load(file,
         width,
         height,
         data_start,
         colors,
         color_depth,
         compression,
         *,
         bitmap=None,
         palette=None):
    """Loads indexed bitmap data into bitmap and palette objects.

    :param file file: The open bmp file
    :param int width: Image width in pixels
    :param int height: Image height in pixels
    :param int data_start: Byte location where the data starts (after headers)
    :param int colors: Number of distinct colors in the image
    :param int color_depth: Number of bits used to store a value
    :param int compression: 0 - none, 1 - 8bit RLE, 2 - 4bit RLE"""
    # pylint: disable=too-many-arguments,too-many-locals,too-many-branches
    if palette:
        palette = palette(colors)

        file.seek(data_start - colors * 4)
        for value in range(colors):
            c_bytes = file.read(4)
            # Need to swap red & blue bytes (bytes 0 and 2)
            palette[value] = bytes(b"".join(
                [c_bytes[2:3], c_bytes[1:2], c_bytes[0:1], c_bytes[3:1]]))

    if bitmap:
        minimum_color_depth = 1
        while colors > 2**minimum_color_depth:
            minimum_color_depth *= 2

        if sys.maxsize > 1073741823:
            # pylint: disable=import-outside-toplevel, relative-beyond-top-level
            from .negative_height_check import negative_height_check

            # convert unsigned int to signed int when height is negative
            height = negative_height_check(height)
        bitmap = bitmap(width, abs(height), colors)
        file.seek(data_start)
        line_size = width // (8 // color_depth)
        if width % (8 // color_depth) != 0:
            line_size += 1
        if line_size % 4 != 0:
            line_size += 4 - line_size % 4

        mask = (1 << minimum_color_depth) - 1
        if height > 0:
            range1 = height - 1
            range2 = -1
            range3 = -1
        else:
            range1 = 0
            range2 = abs(height)
            range3 = 1

        if compression == 0:

            if _bitmap_readinto:
                _bitmap_readinto(
                    bitmap,
                    file,
                    bits_per_pixel=color_depth,
                    element_size=4,
                    reverse_pixels_in_element=True,
                    reverse_rows=True,
                )

            else:  # use the standard file.readinto
                chunk = bytearray(line_size)
                for y in range(range1, range2, range3):
                    file.readinto(chunk)
                    pixels_per_byte = 8 // color_depth
                    offset = y * width

                    for x in range(width):
                        i = x // pixels_per_byte
                        pixel = (chunk[i] >>
                                 (8 - color_depth *
                                  (x % pixels_per_byte + 1))) & mask
                        bitmap[offset + x] = pixel
        elif compression in (1, 2):
            decode_rle(
                bitmap=bitmap,
                file=file,
                compression=compression,
                y_range=(range1, range2, range3),
                width=width,
            )

    return bitmap, palette
Ejemplo n.º 3
0
    def load_glyphs(self, code_points):
        # pylint: disable=too-many-statements,too-many-branches,too-many-nested-blocks,too-many-locals
        if isinstance(code_points, int):
            code_points = (code_points, )
        elif isinstance(code_points, str):
            code_points = [ord(c) for c in code_points]

        code_points = sorted(c for c in code_points
                             if self._glyphs.get(c, None) is None)
        if not code_points:
            return

        indices_offset = self.tables[_PCF_BDF_ENCODINGS].offset + 14
        bitmap_offset_offsets = self.tables[_PCF_BITMAPS].offset + 8
        first_bitmap_offset = self.tables[_PCF_BITMAPS].offset + 4 * (
            6 + self._bitmaps.glyph_count)
        metrics_compressed = self.tables[
            _PCF_METRICS].format & _PCF_COMPRESSED_METRICS
        first_metric_offset = self.tables[_PCF_METRICS].offset + (
            6 if metrics_compressed else 8)
        metrics_size = 5 if metrics_compressed else 12

        # These will each _tend to be_ forward reads in the file, at least
        # sometimes we'll benefit from oofatfs's 512 byte cache and avoid
        # excess reads
        indices = [None] * len(code_points)
        for i, code_point in enumerate(code_points):
            enc1 = (code_point >> 8) & 0xFF
            enc2 = code_point & 0xFF

            if enc1 < self._encoding.min_byte1 or enc1 > self._encoding.max_byte1:
                continue
            if enc2 < self._encoding.min_byte2 or enc2 > self._encoding.max_byte2:
                continue

            encoding_idx = (
                (enc1 - self._encoding.min_byte1) *
                (self._encoding.max_byte2 - self._encoding.min_byte2 + 1) +
                enc2 - self._encoding.min_byte2)
            self.file.seek(indices_offset + 2 * encoding_idx)
            (glyph_idx, ) = self._read(">H")
            if glyph_idx != 65535:
                indices[i] = glyph_idx

        all_metrics = [None] * len(code_points)
        for i, code_point in enumerate(code_points):
            index = indices[i]
            if index is None:
                continue
            self.file.seek(first_metric_offset + metrics_size * index)
            all_metrics[i] = self._read_metrics(metrics_compressed)
        bitmap_offsets = [None] * len(code_points)
        for i, code_point in enumerate(code_points):
            index = indices[i]
            if index is None:
                continue
            self.file.seek(bitmap_offset_offsets + 4 * index)
            (bitmap_offset, ) = self._read(">I")
            bitmap_offsets[i] = bitmap_offset

        # Batch creation of glyphs and bitmaps so that we need only gc.collect
        # once
        gc.collect()
        bitmaps = [None] * len(code_points)
        for i in range(len(all_metrics)):  # pylint: disable=consider-using-enumerate
            metrics = all_metrics[i]
            if metrics is not None:
                width = metrics.right_side_bearing - metrics.left_side_bearing
                height = metrics.character_ascent + metrics.character_descent
                bitmap = bitmaps[i] = self.bitmap_class(width, height, 2)
                self._glyphs[code_points[i]] = Glyph(
                    bitmap,
                    0,
                    width,
                    height,
                    metrics.left_side_bearing,
                    -metrics.character_descent,
                    metrics.character_width,
                    0,
                )

        for i, code_point in enumerate(code_points):
            metrics = all_metrics[i]
            if metrics is None:
                continue
            self.file.seek(first_bitmap_offset + bitmap_offsets[i])
            width = metrics.right_side_bearing - metrics.left_side_bearing
            height = metrics.character_ascent + metrics.character_descent

            bitmap = bitmaps[i]

            if _bitmap_readinto:
                _bitmap_readinto(
                    bitmap,
                    self.file,
                    bits_per_pixel=1,
                    element_size=4,
                    reverse_pixels_in_element=True,
                )
            else:
                words_per_row = (width + 31) // 32
                buf = bytearray(4 * words_per_row)
                start = 0
                for _ in range(height):
                    self.file.readinto(buf)
                    for k in range(width):
                        if buf[k // 8] & (128 >> (k % 8)):
                            bitmap[start + k] = 1
                    start += width