Ejemplo n.º 1
0
    def import_data(self, buffer, parent=None):
        enable = mrc.property_get(self.enable, parent)

        if not enable:
            return mrc.TransformResult(payload=buffer, end_offset=len(buffer))

        output = bytearray(len(buffer) * 2)
        for i in range(len(buffer)):
            output[2 * i] = buffer[i] & 0x0f
            output[2 * i + 1] = buffer[i] >> 4
        return mrc.TransformResult(payload=output, end_offset=len(buffer))
Ejemplo n.º 2
0
 def update_buffer_with_value(self, value, buffer, parent=None):
     super().update_buffer_with_value(value, buffer, parent)
     offset = mrc.property_get(self.offset, parent)
     length = self.get_size(value, parent)
     remainder = value
     if len(buffer) < offset + length:
         buffer.extend(b'\x00' * (offset + length - len(buffer)))
     for i in range(length):
         buffer[offset + i] = remainder & 0x7f
         remainder >>= 7
         if remainder == 0:
             buffer[offset + i] |= 0x80
             break
         remainder -= 1
     return
Ejemplo n.º 3
0
    def export_data(self, buffer, parent=None):
        enable = mrc.property_get(self.enable, parent)

        if not enable:
            return mrc.TransformResult(payload=buffer)

        if buffer:
            assert max(buffer) <= 0xf
        output = bytearray(len(buffer) // 2)
        for i in range(len(buffer)):
            if i % 2:
                output[i // 2] |= buffer[i] << 4
            else:
                output[i // 2] |= buffer[i]
        return mrc.TransformResult(payload=output, end_offset=len(buffer))
Ejemplo n.º 4
0
 def update_buffer_with_value( self, value, buffer, parent=None ):
     super().update_buffer_with_value( value, buffer, parent )
     offset = mrc.property_get( self.offset, parent )
     length = self.get_size( value, parent )
     remainder = value
     if len( buffer ) < offset+length:
         buffer.extend( b'\x00'*(offset+length-len( buffer )) )
     for i in range( length ):
         buffer[offset+i] = remainder & 0x7f
         remainder >>= 7
         if remainder == 0:
             buffer[offset+i] |= 0x80
             break
         remainder -= 1
     return
Ejemplo n.º 5
0
 def get_from_buffer(self, buffer, parent=None):
     assert utils.is_bytes(buffer)
     offset = mrc.property_get(self.offset, parent)
     pointer = offset
     total = 0
     shift = 0
     while pointer < len(buffer):
         test = buffer[pointer]
         pointer += 1
         total += (test & 0x7f) << shift
         shift += 7
         if test & 0x80:
             break
         total += 1 << shift
     return total
Ejemplo n.º 6
0
 def get_from_buffer( self, buffer, parent=None ):
     assert utils.is_bytes( buffer )
     offset = mrc.property_get( self.offset, parent )
     pointer = offset
     total = 0
     shift = 0
     while pointer < len( buffer ):
         test = buffer[pointer]
         pointer += 1 
         total += (test & 0x7f) << shift
         shift += 7
         if test & 0x80:
             break
         total += 1 << shift
     return total
Ejemplo n.º 7
0
    def export_data(self, buffer: bytes, parent=None):
        assert utils.is_bytes(buffer)

        # load in constructor properties
        bpp = mrc.property_get(self.bpp, parent)
        width = mrc.property_get(self.width, parent)
        height = mrc.property_get(self.height, parent)
        plane_size = mrc.property_get(self.plane_size, parent)
        plane_padding = mrc.property_get(self.plane_padding, parent)
        frame_offset = mrc.property_get(self.frame_offset, parent)
        frame_count = mrc.property_get(self.frame_count, parent)
        frame_stride = mrc.property_get(self.frame_stride, parent)

        assert (bpp >= 0) and (bpp <= 8)
        if (width or height):
            assert (width * height) % 8 == 0
            if plane_size:
                raise Exception(
                    'Can\'t define plane_size when either width or height is defined.'
                )
        elif plane_size is None and frame_count == 1:
            # for a single frame without a plane size, assume the buffer contains everything
            assert len(buffer) % bpp == 0
            plane_size = len(buffer) // bpp
        else:
            assert plane_size is not None

        if not plane_size:
            plane_size = math.ceil(width * height / 8)

        assert (frame_count >= 1)
        if frame_count >= 2 and frame_stride is None:
            frame_stride = bpp * (plane_size + plane_padding)
        else:
            frame_stride = frame_stride if frame_stride is not None else 0

        if frame_count == 1:
            assert len(buffer) >= frame_offset + plane_size * 8
        else:
            assert len(buffer) >= frame_offset + frame_count * frame_stride

        # this method just does the opposite of the above; split chunky pixels back into planes.
        planes = array('Q')
        segment_size = plane_size + plane_padding
        if frame_count == 1:
            raw_planes = bytearray(frame_offset + segment_size * bpp)
        else:
            raw_planes = bytearray(frame_offset + frame_count * frame_stride)

        for f in range(frame_count):
            pointer = frame_offset + f * frame_stride
            planes = planes[0:0]
            # load our chunky pixels into the 64-bit int array
            planes.frombytes(buffer[f * plane_size * 8:(f + 1) * plane_size *
                                    8])
            # check for endianness!
            if sys.byteorder == 'little':
                planes.byteswap()

            for b in range(bpp):
                for i in range(plane_size):
                    # for each group of 8 chunky pixels, use pack_bits to fill up 8 bits
                    # of the relevant bitplane
                    raw_planes[pointer + b * segment_size +
                               i] = bits.pack_bits((planes[i] >> b))

        return mrc.TransformResult(payload=raw_planes)
Ejemplo n.º 8
0
    def import_data(self, buffer: bytes, parent=None):
        assert utils.is_bytes(buffer)

        # load in constructor properties
        bpp = mrc.property_get(self.bpp, parent)
        width = mrc.property_get(self.width, parent)
        height = mrc.property_get(self.height, parent)
        plane_size = mrc.property_get(self.plane_size, parent)
        plane_padding = mrc.property_get(self.plane_padding, parent)
        frame_offset = mrc.property_get(self.frame_offset, parent)
        frame_count = mrc.property_get(self.frame_count, parent)
        frame_stride = mrc.property_get(self.frame_stride, parent)
        row_planar_size = mrc.property_get(self.row_planar_size, parent)
        plane_order = mrc.property_get(self.plane_order, parent)

        assert (bpp >= 0) and (bpp <= 8)
        if (width or height):
            assert (width * height) % 8 == 0
            if plane_size:
                raise Exception(
                    'Can\'t define plane_size when either width or height is defined.'
                )
        elif plane_size is None and frame_count == 1:
            # for a single frame without a plane size, assume the buffer contains everything
            assert len(buffer) % bpp == 0
            plane_size = len(buffer) // bpp
        else:
            assert plane_size is not None
        assert (frame_count >= 1)

        if plane_size is None:
            plane_size = math.ceil(width * height / 8)

        if frame_count >= 2 and frame_stride is None:
            frame_stride = bpp * (plane_size + plane_padding)
        else:
            frame_stride = frame_stride if frame_stride is not None else 0

        if row_planar_size:
            assert row_planar_size >= 1

        if not plane_order:
            plane_order = range(bpp)
        else:
            assert all([y in range(bpp) for y in plane_order])
            assert len(plane_order) == len(set(plane_order))

        # because frame_stride can potentially read past the buffer, only worry about measuring
        # the last n-1 strides + one frame
        assert len(buffer) >= frame_offset + (
            frame_count - 1) * frame_stride + bpp * plane_size

        # our output is going to be "chunky"; each byte is a pixel (8-bit or 256 colour mode)
        raw_image = bytearray(plane_size * frame_count)

        # the input is planar. this is a packed format found occasionally in old graphics hardware,
        # and in old image formats where space was paramount.
        # the trick is you can have less than 8 bits in your colourspace!
        # e.g. if you only need 8 colours, you can get away with a 3-bit colourspace and save 62.5% space.
        # instead of each byte being a pixel, each byte stores 8 pixels worth of data for a single plane.
        # there is one plane per bit of colourspace, and the planes are stored one after another.

        # in order for the calculations to be fast, planar graphics are pretty much always divisible by 8.
        # we're going to abuse this and unpack our bitplanes using 64-bit integers.
        # let's make a big array of them.
        planes = array('Q', (0, ) * (plane_size))
        segment_size = plane_size + plane_padding

        for f in range(frame_count):
            pointer = frame_offset + f * frame_stride
            for bi, b in enumerate(plane_order):
                for i in range(plane_size):
                    # for the first iteration, clear the plane
                    if bi == 0:
                        planes[i] = 0

                    if row_planar_size is None:
                        address = pointer + b * segment_size + i
                    else:
                        address = pointer + (row_planar_size * bpp) * (
                            i // row_planar_size) + row_planar_size * b + (
                                i % row_planar_size)

                    # bits.unpack_bits is a helper method which converts a 1-byte bitfield
                    # into 8 bool bytes (i.e. 1 or 0) stored as a 64-bit int.
                    # we can effectively work on 8 chunky pixels at once!
                    # because the chunky pixels are bitfields, combining planes is an easy
                    # left shift (i.e. move all the bits up by [plane ID] places) and bitwise OR
                    planes[i] |= bits.unpack_bits(buffer[address]) << bi

            # check for endianness! for most intel and ARM chips the order of bytes in hardware is reversed,
            # so we need to flip it around for the bytes to be sequential.
            if sys.byteorder == 'little':
                planes.byteswap()

            # convert our planes array to bytes, and you have your chunky pixels
            raw_image[f * plane_size * 8:(f + 1) * plane_size *
                      8] = planes.tobytes()

        if frame_count > 1:
            end_offset = frame_offset + frame_count * frame_stride
        else:
            plane_bits = plane_size * 8 * bpp
            end_offset = frame_offset + (plane_bits) // 8 + (1 if (plane_bits %
                                                                   8) else 0)

        return mrc.TransformResult(payload=bytes(raw_image),
                                   end_offset=end_offset)
Ejemplo n.º 9
0
    def ansi_format_iter(self,
                         x_start=0,
                         y_start=0,
                         width=None,
                         height=None,
                         frame=0,
                         columns=1,
                         downsample=1,
                         frame_index=None,
                         frame_flip_v=0,
                         frame_flip_h=0):
        """Return the ANSI escape sequence to render the image.

        x_start
            Offset from the left of the image data to render from. Defaults to 0.

        y_start
            Offset from the top of the image data to render from. Defaults to 0.

        width
            Width of the image data to render. Defaults to the image width.

        height
            Height of the image data to render. Defaults to the image height.

        frame
            Single frame number/object, or a list of frames to render in sequence. Defaults to frame 0.

        columns
            Number of frames to render per line (useful for printing tilemaps!). Defaults to 1.

        downsample
            Shrink larger images by printing every nth pixel only. Defaults to 1.

        frame_index
            Constant or mrc.Ref for a frame object property denoting the index. Defaults to None
            (i.e. frame itself should be an index).

        frame_flip_v
            Constant or mrc.Ref for a frame object property for whether to mirror vertically.
            Defaults to 0.

        frame_flip_h
            Constant or mrc.Ref for a frame object property for whether to mirror horizontally.
            Defaults to 0.
        """

        assert x_start in range(0, self.width)
        assert y_start in range(0, self.height)
        if frame_index is not None:
            fn_index = lambda fr: mrc.property_get(frame_index, fr)
        else:
            fn_index = lambda fr: fr if fr in range(0, self.frame_count
                                                    ) else None
        fn_flip_v = lambda fr: mrc.property_get(frame_flip_v, fr)
        fn_flip_h = lambda fr: mrc.property_get(frame_flip_h, fr)

        frames = []
        try:
            frame_iter = iter(frame)
            frames = [f for f in frame_iter]
        except TypeError:
            frames = [frame]

        if not width:
            width = self.width - x_start
        if not height:
            height = self.height - y_start

        stride = width * height
        image_size = stride * self.frame_count
        self.overflow = False
        self.overflow_area = ''
        self.overflow_size = 0

        def data_fetch(x, y, fr_obj):
            fr = fn_index(fr_obj)
            if fr is None:
                return Transparent()
            if not ((0 <= x < self.width) and (0 <= y < self.height)):
                return Transparent()
            if fn_flip_h(fr_obj):
                x = self.width - x - 1
            if fn_flip_v(fr_obj):
                y = self.height - y - 1
            index = self.width * y + x
            offset = stride * fr + index

            if offset >= len(self.source):
                if not self.overflow:
                    self.overflow = True
                    self.overflow_area = 'source'
                    self.overflow_size = len(self.source)
                return Transparent()
            p = self.source[offset]
            if self.mask:
                if offset >= len(self.mask):
                    if not self.overflow:
                        self.overflow = True
                        self.overflow_area = 'mask'
                        self.overflow_size = len(self.mask)
                    return Transparent()
                p = p if self.mask[offset] else None
            return self.palette[p] if p is not None else Transparent()

        for x in ansi.format_image_iter(data_fetch, x_start, y_start, width,
                                        height, frames, columns, downsample):
            yield x
        if self.overflow:
            logger.warning(
                'Image {} requires {} pixels but {} only has {} pixels'.format(
                    self, image_size, self.overflow_area, self.overflow_size))
        return
Ejemplo n.º 10
0
 def get_start_offset(self, value, parent=None, index=None):
     assert index is None
     offset = mrc.property_get(self.offset, parent)
     return offset
Ejemplo n.º 11
0
    def export_data( self, buffer: bytes, parent=None ):
        assert utils.is_bytes( buffer )

        # load in constructor properties
        bpp = mrc.property_get( self.bpp, parent )
        width = mrc.property_get( self.width, parent )
        height = mrc.property_get( self.height, parent )
        plane_size = mrc.property_get( self.plane_size, parent )
        plane_padding = mrc.property_get( self.plane_padding, parent )
        frame_offset = mrc.property_get( self.frame_offset, parent )
        frame_count = mrc.property_get( self.frame_count, parent )
        frame_stride = mrc.property_get( self.frame_stride, parent )

        assert (bpp >= 0) and (bpp <= 8)
        if (width or height):
            assert (width*height) % 8 == 0
            if plane_size:
                raise Exception( 'Can\'t define plane_size when either width or height is defined.' )
        elif plane_size is None and frame_count == 1:
            # for a single frame without a plane size, assume the buffer contains everything
            assert len( buffer ) % bpp == 0
            plane_size = len( buffer ) // bpp
        else:
             assert plane_size is not None

        if not plane_size:
            plane_size = math.ceil( width*height/8 )

        assert (frame_count >= 1)
        if frame_count >= 2 and frame_stride is None:
            frame_stride = bpp*(plane_size+plane_padding)
        else:
            frame_stride = frame_stride if frame_stride is not None else 0

        if frame_count == 1:
            assert len( buffer ) >= frame_offset + plane_size*8 
        else:
            assert len( buffer ) >= frame_offset + frame_count*frame_stride

        # this method just does the opposite of the above; split chunky pixels back into planes.
        planes = array( 'Q' )
        segment_size = plane_size+plane_padding
        if frame_count == 1:
            raw_planes = bytearray( frame_offset+segment_size*bpp )
        else:
            raw_planes = bytearray( frame_offset+frame_count*frame_stride )
    
        for f in range( frame_count ):
            pointer = frame_offset+f*frame_stride
            planes = planes[0:0]
            # load our chunky pixels into the 64-bit int array
            planes.frombytes( buffer[f*plane_size*8:(f+1)*plane_size*8] )
            # check for endianness!
            if sys.byteorder == 'little':
                planes.byteswap()

            for b in range( bpp ):
                for i in range( plane_size ):
                    # for each group of 8 chunky pixels, use pack_bits to fill up 8 bits
                    # of the relevant bitplane
                    raw_planes[pointer+b*segment_size+i] = utils.pack_bits( (planes[i] >> b) )

        return mrc.TransformResult( payload=raw_planes )
Ejemplo n.º 12
0
    def import_data( self, buffer: bytes, parent=None ):
        assert utils.is_bytes( buffer )

        # load in constructor properties
        bpp = mrc.property_get( self.bpp, parent )
        width = mrc.property_get( self.width, parent )
        height = mrc.property_get( self.height, parent )
        plane_size = mrc.property_get( self.plane_size, parent )
        plane_padding = mrc.property_get( self.plane_padding, parent )
        frame_offset = mrc.property_get( self.frame_offset, parent )
        frame_count = mrc.property_get( self.frame_count, parent )
        frame_stride = mrc.property_get( self.frame_stride, parent )
        row_planar_size = mrc.property_get( self.row_planar_size, parent )
        plane_order = mrc.property_get( self.plane_order, parent )


        assert (bpp >= 0) and (bpp <= 8)
        if (width or height):
            assert (width*height) % 8 == 0
            if plane_size:
                raise Exception( 'Can\'t define plane_size when either width or height is defined.' )
        elif plane_size is None and frame_count == 1:
            # for a single frame without a plane size, assume the buffer contains everything
            assert len( buffer ) % bpp == 0
            plane_size = len( buffer ) // bpp
        else:
            assert plane_size is not None
        assert (frame_count >= 1)

        if plane_size is None:
            plane_size = math.ceil( width*height/8 )

        if frame_count >= 2 and frame_stride is None:
            frame_stride = bpp*(plane_size+plane_padding)
        else:
            frame_stride = frame_stride if frame_stride is not None else 0

        if row_planar_size:
            assert row_planar_size >= 1
        
        if not plane_order:
            plane_order = range( bpp )
        else: 
            assert all( [y in range( bpp ) for y in plane_order] )
            assert len( plane_order ) == len( set( plane_order ) )

        # because frame_stride can potentially read past the buffer, only worry about measuring
        # the last n-1 strides + one frame
        assert len( buffer ) >= frame_offset + (frame_count-1)*frame_stride + bpp*plane_size


        # our output is going to be "chunky"; each byte is a pixel (8-bit or 256 colour mode)
        raw_image = bytearray( plane_size*frame_count )

        # the input is planar. this is a packed format found occasionally in old graphics hardware,
        # and in old image formats where space was paramount.
        # the trick is you can have less than 8 bits in your colourspace! 
        # e.g. if you only need 8 colours, you can get away with a 3-bit colourspace and save 62.5% space.
        # instead of each byte being a pixel, each byte stores 8 pixels worth of data for a single plane.
        # there is one plane per bit of colourspace, and the planes are stored one after another.
        
        # in order for the calculations to be fast, planar graphics are pretty much always divisible by 8.
        # we're going to abuse this and unpack our bitplanes using 64-bit integers.
        # let's make a big array of them.
        planes = array( 'Q', (0,)*(plane_size) )
        segment_size = plane_size+plane_padding
    
        for f in range( frame_count ):
            pointer = frame_offset+f*frame_stride
            for bi, b in enumerate( plane_order ):
                for i in range( plane_size ):
                    # for the first iteration, clear the plane
                    if bi==0:
                        planes[i] = 0

                    if row_planar_size is None:
                        address = pointer+b*segment_size+i
                    else:
                        address = pointer + (row_planar_size*bpp)*(i // row_planar_size) + row_planar_size*b + (i % row_planar_size)

                    # utils.unpack_bits is a helper method which converts a 1-byte bitfield
                    # into 8 bool bytes (i.e. 1 or 0) stored as a 64-bit int.
                    # we can effectively work on 8 chunky pixels at once!
                    # because the chunky pixels are bitfields, combining planes is an easy
                    # left shift (i.e. move all the bits up by [plane ID] places) and bitwise OR
                    planes[i] |= utils.unpack_bits( buffer[address] ) << bi
                    
            # check for endianness! for most intel and ARM chips the order of bytes in hardware is reversed,
            # so we need to flip it around for the bytes to be sequential.
            if sys.byteorder == 'little':
                planes.byteswap()

            # convert our planes array to bytes, and you have your chunky pixels
            raw_image[f*plane_size*8:(f+1)*plane_size*8] = planes.tobytes()

        if frame_count > 1:
            end_offset = frame_offset + frame_count*frame_stride
        else:
            bits = plane_size*8*bpp
            end_offset = frame_offset + (bits)//8 + (1 if (bits % 8) else 0)

        return mrc.TransformResult( payload=bytes( raw_image ), end_offset=end_offset )
Ejemplo n.º 13
0
    def ansi_format_iter( self, x_start=0, y_start=0, width=None, height=None, frame=0, columns=1, downsample=1, frame_index=None, frame_flip_v=0, frame_flip_h=0 ):
        """Return the ANSI escape sequence to render the image.

        x_start
            Offset from the left of the image data to render from. Defaults to 0.

        y_start
            Offset from the top of the image data to render from. Defaults to 0.

        width
            Width of the image data to render. Defaults to the image width.

        height
            Height of the image data to render. Defaults to the image height.

        frame
            Single frame number/object, or a list of frames to render in sequence. Defaults to frame 0.

        columns
            Number of frames to render per line (useful for printing tilemaps!). Defaults to 1.

        downsample
            Shrink larger images by printing every nth pixel only. Defaults to 1.

        frame_index
            Constant or mrc.Ref for a frame object property denoting the index. Defaults to None
            (i.e. frame itself should be an index).

        frame_flip_v
            Constant or mrc.Ref for a frame object property for whether to mirror vertically.
            Defaults to 0.

        frame_flip_h
            Constant or mrc.Ref for a frame object property for whether to mirror horizontally.
            Defaults to 0.
        """

        assert x_start in range( 0, self.width )
        assert y_start in range( 0, self.height )
        if frame_index is not None:
            fn_index = lambda fr: mrc.property_get( frame_index, fr )
        else:
            fn_index = lambda fr: fr if fr in range( 0, self.frame_count ) else None
        fn_flip_v = lambda fr: mrc.property_get( frame_flip_v, fr )
        fn_flip_h = lambda fr: mrc.property_get( frame_flip_h, fr )

        frames = []
        try:
            frame_iter = iter( frame )
            frames = [f for f in frame_iter]
        except TypeError:
            frames = [frame]

        if not width:
            width = self.width-x_start
        if not height:
            height = self.height-y_start

        stride = width*height

        def data_fetch( x, y, fr_obj ):
            fr = fn_index( fr_obj )
            if fr is None:
                return Transparent()
            if not ((0 <= x < self.width) and (0 <= y < self.height)):
                return Transparent()
            if fn_flip_h( fr_obj ):
                x = self.width - x - 1
            if fn_flip_v( fr_obj ):
                y = self.height - y - 1
            index = self.width*y + x
            p = self.source[stride*fr+index]
            if self.mask:
                p = p if self.mask[stride*fr+index] else None
            return self.palette[p] if p is not None else Transparent()

        for x in ansi.format_image_iter( data_fetch, x_start, y_start, width, height, frames, columns, downsample ):
            yield x
        return
Ejemplo n.º 14
0
 def get_start_offset( self, value, parent=None, index=None ):
     assert index is None
     offset = mrc.property_get( self.offset, parent )
     return offset