Esempio n. 1
0
 def getc():
     c = infile.read(1)
     if not c:
         if not allow_eof or EOF[0]:
             raise png.Error('premature End of file')
         else:
             # small hack to simulate trailing whitespace at the end of file
             EOF[0] = True  # but only once
             return ' '
     return c
Esempio n. 2
0
def deblock(f):
    """
    Decompress a single block from a compressed Plan 9 image file.

    Each block starts with 2 decimal strings of 12 bytes each.  Yields a
    sequence of (row, data) pairs where row is the total number of rows
    processed according to the file format and data is the decompressed
    data for a set of rows.
    """
    row = int(f.read(12))
    size = int(f.read(12))
    if not (0 <= size <= 6000):
        raise 'block has invalid size; not a Plan 9 image file?'
    # Since each block is at most 6000 bytes we may as well read it all in
    # one go.
    d = f.read(size)
    i = 0
    o = []

    while i < size:
        x = ord(d[i:i + 1])  # hack to avoid interpreting bytes item as int
        i += 1
        if x & 0x80:
            x = (x & 0x7f) + 1
            lit = d[i:i + x]
            i += x
            o.extend(lit)
            continue
        # x's high-order bit is 0
        l = (x >> 2) + 3
        # Offset is made from bottom 2 bits of x and all 8 bits of next
        # byte.  http://plan9.bell-labs.com/magic/man2html/6/image doesn't
        # say whether x's 2 bits are most significant or least significant.
        # But it is clear from inspecting a random file,
        # http://plan9.bell-labs.com/sources/plan9/sys/games/lib/sokoban/images/cargo.bit
        # that x's 2 bit are most significant.
        offset = (x & 3) << 8
        offset |= ord(d[i:i + 1])
        i += 1
        # Note: complement operator neatly maps (0 to 1023) to (-1 to
        # -1024).  Adding len(o) gives a (non-negative) offset into o from
        # which to start indexing.
        offset = ~offset + len(o)
        if offset < 0:
            raise png.Error('byte offset indexes off the begininning'
                            'of the output buffer; not a Plan 9 image file?')
        for j in range(l):
            o.append(o[offset + j])
    try:
        res = ''.join(o)
    except:
        res = bytearray(o)
    return row, res
Esempio n. 3
0
def read_pam_header(infile):
    """
    Read (the rest of a) PAM header.

    `infile` should be positioned
    immediately after the initial 'P7' line (at the beginning of the
    second line).  Returns are as for `read_pnm_header`.
    """
    # Unlike PBM, PGM, and PPM, we can read the header a line at a time.
    header = dict()
    while True:
        l = infile.readline().strip()
        if l == png.strtobytes('ENDHDR'):
            break
        if not l:
            raise EOFError('PAM ended prematurely')
        if l[0] == png.strtobytes('#'):
            continue
        l = l.split(None, 1)
        if l[0] not in header:
            header[l[0]] = l[1]
        else:
            header[l[0]] += png.strtobytes(' ') + l[1]

    required = ['WIDTH', 'HEIGHT', 'DEPTH', 'MAXVAL']
    required = [png.strtobytes(x) for x in required]
    WIDTH, HEIGHT, DEPTH, MAXVAL = required
    present = [x for x in required if x in header]
    if len(present) != len(required):
        raise png.Error('PAM file must specify '
                        'WIDTH, HEIGHT, DEPTH, and MAXVAL')
    width = int(header[WIDTH])
    height = int(header[HEIGHT])
    depth = int(header[DEPTH])
    maxval = int(header[MAXVAL])
    if (width <= 0 or height <= 0 or depth <= 0 or maxval <= 0):
        raise png.Error(
            'WIDTH, HEIGHT, DEPTH, MAXVAL must all be positive integers')
    return 'P7', width, height, depth, maxval
Esempio n. 4
0
def read_int_tokens(infile, n, allow_eof=False):
    """
    Read ASCII integers separated with whitespaces as list of length `n`

    Skip comments started with '#' to the end of line
    If comment starts right after digit and newline starts with digit
    these digits form single number.
    """
    result = []
    EOF = [False]  # Hack to allow modification in nested function

    # We may consume less or more than one line, so characters read one by one
    def getc():
        c = infile.read(1)
        if not c:
            if not allow_eof or EOF[0]:
                raise png.Error('premature End of file')
            else:
                # small hack to simulate trailing whitespace at the end of file
                EOF[0] = True  # but only once
                return ' '
        return c

    token = bytes()
    while True:
        c = getc()
        if c.isspace():
            if token:
                # post-token whitespace, save token
                result.append(int(token))
                if len(result) == n:
                    # we get here on last whitespace
                    break
                # and clean for new token
                token = bytes()
            # Skip whitespace that precedes a token or between tokens.
        elif c == png.strtobytes('#'):
            # Skip comments to the end of line.
            infile.readline()
            # If there is no whitespaces after conventional newline
            # continue reading token
        elif c.isdigit():
            token += c
        else:
            raise png.Error('unexpected character %s found ' % c)
    return result