Exemplo n.º 1
0
def main(argv=None):
    argv = argv or sys.argv
    op = argv[1]
    filename = argv[2]
    if op == 'font':
        w = int(argv[3])
        h = int(argv[4])
        title = argv[5]
        print(cvt_font(filename, 24, 32, '0;1', title))
        return
    if op == 'img':
        starttile = int(argv[3])
        title = argv[4]
        im = Image.open(filename)
        c = pilbmp2chr(im, 8, 8, lambda k: formatTilePlanar(k, '0;1'))
        tiles, itiles, nam = chrtonam(c)
        nam = bytearray(starttile + c for c in nam)
        tiles = b''.join(tiles)
        ctiles = zeroelim(tiles)
        out = [
            "; image converted with cvtfont.py",
            ".export %s_zet, %s_chr_size, %s_nam" % (title, title, title),
            ".exportzp %s_w, %s_h" % (title, title), '.segment "RODATA"',
            "%s_w = %d" % (title, (im.size[0] + 7) // 8),
            "%s_h = %d" % (title, (im.size[1] + 7) // 8),
            "%s_chr_size = %d" % (title, len(tiles)),
            "%s_zet:" % title,
            ca65_bytearray(ctiles),
            "%s_nam:" % title,
            ca65_bytearray(nam)
        ]
        print('\n'.join(out))
        return
Exemplo n.º 2
0
def main(argv=None):
    argv = argv or sys.argv
    infilename, outfilename = argv[1:3]
    im = Image.open(infilename)
    tiles = pilbmp2chr(im, formatTile=snesformat)
    utiles, tilemap = flipuniq(tiles)
    assert len(utiles) <= 64
    pbtiles = b"".join(pb16.pb16(b"".join(utiles)))
    tmrows = [bytes(tilemap[i:i + 32]) for i in range(0, len(tilemap), 32)]
    utmrows, tmrowmap = uniq(tmrows)
    iutmrows = iur_encode_tilemap(b''.join(utmrows))

    palette = im.getpalette()[:48]
    snespalette = bytearray()
    for i in range(0, 48, 3):
        r = palette[i] >> 3
        g = palette[i + 1] >> 3
        b = palette[i + 2] >> 3
        bgr = (b << 10) | (g << 5) | r
        snespalette.append(bgr & 0xFF)
        snespalette.append(bgr >> 8)

    out = b"".join(
        (bytes([len(utiles) * 2]), pbtiles, bytes([16 * len(utmrows)]),
         iutmrows, bytes(tmrowmap), snespalette))
    with open(outfilename, "wb") as outfp:
        outfp.write(out)
Exemplo n.º 3
0
def read_strip(im, strip, g2l, hotspot, tile_ht):
    paletteid, l, t, w, h, lpad, tpad, dstl, dstt = strip

    # Crop and convert to subpalette
    cropped = im.crop((l, t, l + w, t + h)).point(g2l[paletteid])

    # Add padding at left and top for exceeding the crop rect,
    # and at right and bottom to a multiple of one tile
    wnew = -(-(w + lpad) // TILE_W) * TILE_W
    hnew = -(-(h + tpad) // tile_ht) * tile_ht
    padded = Image.new('P', (wnew, hnew), 0)
    padded.paste(cropped, (lpad, tpad))

    # Convert image to tiles
    tilefmt = lambda x: pilbmp2nes.formatTilePlanar(x, TILE_PLANEMAP)
    striptiles = pilbmp2nes.pilbmp2chr(padded, TILE_W, tile_ht, tilefmt)

    # Convert coords to hotspot-relative
    dstl -= hotspot[0]
    dstt -= hotspot[1]

    # Convert tiles to horizontal strips
    tperrow = (tile_ht // 8) * (wnew // 8)
    tend = 0
    for y in range(hnew // tile_ht):
        tstart, tend = tend, tend + tperrow
        yield paletteid, striptiles[tstart:tend], dstl, dstt + y * tile_ht
Exemplo n.º 4
0
def main(argv=None):
    argv = argv or sys.argv
    specfilename = argv[1]
    imname = argv[2]
    outfilename = argv[3]
    lines = load_spec_file(specfilename)
    coords = []
    for line in lines:
        coord = [x.strip() for x in line.split(',')]
        if len(coord) != 2 or not all(x.isdigit() for x in coord):
            print("%s is not coords" % line, sys.stderr)
            continue
        coords.append(tuple(int(x) for x in coord))

    im = Image.open(imname)
    if im.mode != 'P':
        print("mkspritemap.py: %s must be indexed" % imname,
              file=sys.stderr))
        sys.exit(1)

    overdraw = [0]*im.size[1]
    alltiles = []
    out = array.array('B', [len(coords)])
    for left, top in coords:
        out.extend((left, top))
        for y in xrange(top, top + 8):
            overdraw[y] += 1
        tdata = pilbmp2chr(im.crop((left, top, left+8, top+8)))
        alltiles.extend(tdata)
    compressed = pb53.pb53(''.join(alltiles))[0]
    out.fromstring(compressed)
    print("Num tiles: %d; max overdraw: %d; data size: %d bytes"
          % (len(alltiles), max(overdraw), len(compressed)))
Exemplo n.º 5
0
def test_iur():
    from PIL import Image
    from pilbmp2nes import pilbmp2chr, formatTilePlanar

    gbformat = lambda tile: formatTilePlanar(tile, "0,1")
    test_filenames = [
        ("Proposed MF title screen",
         "../renders/title_bgonly.png"),
        ("Green Hill Zone for GB",
         "../../240p-test-mini/gameboy/tilesets/greenhillzone.png"),
        ("Gus portrait for DMG",
         "../../240p-test-mini/gameboy/tilesets/Gus_portrait.png"),
        ("Linearity quadrant for GB",
         "../../240p-test-mini/gameboy/tilesets/linearity-quadrant.png"),
        ("Sharpness for GB",
         "../../240p-test-mini/gameboy/tilesets/sharpness.png"),
        ("Stopwatch face for GB",
         "../../240p-test-mini/gameboy/tilesets/stopwatchface.png"),
    ]
    for title, filename in test_filenames:
        print("Stats for %s (%s)" % (title, os.path.basename(filename)))
        im = Image.open(filename)
        chrdata = pilbmp2chr(im, formatTile=gbformat)
        iur_encode(chrdata, report=True)
        print()
Exemplo n.º 6
0
def im_to_gbc(im, palettes):
    imfinal, attrs = colorround(im, palettes, (8, 8), 4)
    gbformat = lambda im: formatTilePlanar(im, "0,1")
    tiles = pilbmp2chr(imfinal, formatTile=formatTileGB)
    utiles, tilemap = flipuniq(tiles)
    assert len(tilemap) == len(attrs)
    tilemap_hi = bytearray((t >> 8) | c for t, c in zip(tilemap, attrs))
    tilemap_lo = bytearray(t & 0xFF for t in tilemap)
    return imfinal, utiles, tilemap_lo, tilemap_hi
Exemplo n.º 7
0
def bmptowidesb53(infilename, palette, outfilename):
    im = Image.open(infilename)
    if im.size[0] != 512:
        raise ValueError("Image width is %d pixels (expected 512)" %
                         im.size[0])
    if im.size[1] != 240:
        raise ValueError("Image height is %d pixels (expected 240)" %
                         im.size[0])

    # Quantize picture to palette
    palette = b''.join(palette[0:1] + palette[i + 1:i + 4]
                       for i in range(0, 16, 4))
    palettes = [[tuple(savtool.bisqpal[r]) for r in palette[i:i + 4]]
                for i in range(0, 16, 4)]
    imf, attrs = savtool.colorround(im, palettes)

    # Convert to unique tiles
    chrdata = pilbmp2nes.pilbmp2chr(imf, 8, 8)
    chrdata, linear_namdata = chnutils.dedupe_chr(chrdata)
    print("%d distinct tiles" % len(chrdata))

    # Split into separate 32x32 nametables
    nametables = [[
        linear_namdata[i:i + 32]
        for i in range(x, len(linear_namdata), im.size[0] // 8)
    ] for x in range(0, im.size[0] // 8, 32)]
    nametables = [bytes(b for row in nt for b in row) for nt in nametables]

    # Pack attributes into bytes
    if len(attrs) % 2:
        attrs.append([0] * len(attrs[0]))
    attrs = [[lc | (rc << 2) for lc, rc in zip(row[0::2], row[1::2])]
             for row in attrs]
    attrs = [[tc | (bc << 4) for (tc, bc) in zip(t, b)]
             for (t, b) in zip(attrs[0::2], attrs[1::2])]
    # Split into separate 32x32 nametables
    attrs = [
        bytes(b for row in attrs for b in row[i:i + 8])
        for i in range(0, len(attrs[0]), 8)
    ]
    print([len(x) for x in attrs])

    outdata = [
        bytearray([len(chrdata) & 0xFF]),
        pb53(b''.join(chrdata), copyprev=False)[0]
    ]
    outdata.extend(
        pb53(nt + at, copyprev=False)[0] for nt, at in zip(nametables, attrs))
    outdata.append(palette)
    with open(outfilename, 'wb') as outfp:
        outfp.writelines(outdata)
Exemplo n.º 8
0
def bmptowidesb53(infilename, palette, outfilename):
    im = Image.open(infilename)
    if im.size[0] != 512:
        raise ValueError("Image width is %d pixels (expected 512)"
                         % im.size[0])
    if im.size[1] != 240:
        raise ValueError("Image height is %d pixels (expected 240)"
                         % im.size[0])

    # Quantize picture to palette
    palette = b''.join(palette[0:1] + palette[i + 1:i + 4]
                       for i in range(0, 16, 4))
    palettes = [[tuple(savtool.bisqpal[r]) for r in palette[i:i + 4]]
                 for i in range(0, 16, 4)]
    imf, attrs = savtool.colorround(im, palettes)

    # Convert to unique tiles    
    chrdata = pilbmp2nes.pilbmp2chr(imf, 8, 8)
    chrdata, linear_namdata = chnutils.dedupe_chr(chrdata)
    print("%d distinct tiles" % len(chrdata))

    # Split into separate 32x32 nametables
    nametables = [[linear_namdata[i:i + 32]
                   for i in range(x, len(linear_namdata), im.size[0] // 8)]
                  for x in range(0, im.size[0] // 8, 32)]
    nametables = [bytes(b for row in nt for b in row) for nt in nametables]

    # Pack attributes into bytes
    if len(attrs) % 2:
        attrs.append([0] * len(attrs[0]))
    attrs = [[lc | (rc << 2) for lc, rc in zip(row[0::2], row[1::2])]
             for row in attrs]
    attrs = [[tc | (bc << 4) for (tc, bc) in zip(t, b)]
             for (t, b) in zip(attrs[0::2], attrs[1::2])]
    # Split into separate 32x32 nametables
    attrs = [bytes(b for row in attrs for b in row[i:i + 8])
             for i in range(0, len(attrs[0]), 8)]
    print([len(x) for x in attrs])

    outdata = [
        bytearray([len(chrdata) & 0xFF]),
        pb53(b''.join(chrdata), copyprev=False)[0]
    ]
    outdata.extend(pb53(nt + at, copyprev=False)[0]
                   for nt, at in zip(nametables, attrs))
    outdata.append(palette)
    with open(outfilename, 'wb') as outfp:
        outfp.writelines(outdata)
Exemplo n.º 9
0
def load_glyph_tiles_from(filename, cellw, cellh, fmt):
    """Load tiles from glyphs in filename.

im -- PIL image object in indexed color or filename to load
cellw -- width of each glyph box, multiple of 8
cellh -- height of glyph box, multiple of 8
fmt -- a pilbmp2nes planemap string, such as "0,1" for GB or "0;1" for NES

The glyphs in `im` are left-aligned in their boxes, using color 0
for transparent and the highest color value for space between glyphs.

Return a list of lists of tiles in column-major order.

"""
    if isinstance(filename, str):
        im = Image.open(filename)
    else:
        im, filename = filename, '<image>'
    if im.mode != 'P':
        raise ValueError("%s: not indexed color" % filename)
    st = ImageStat.Stat(im)
    bordercolor = st.extrema[0][1]

    # Crop each glyph out of the image
    portions = (im.crop((x, y, x + cellw, y + cellh))
                for y in range(0, im.size[1], cellh)
                for x in range(0, im.size[0], cellw))

    # Crop out the internal border to right of each glyph
    # ImageChops.difference(im, flat).getbbox(): thanks Eugene Nagorny
    # http://stackoverflow.com/q/10615901/2738262
    flatborder = Image.new(im.mode, (cellw, cellh), bordercolor)
    bboxes = ((portion, ImageChops.difference(portion, flatborder).getbbox())
              for portion in portions)

    portionsC = (portion.crop(bb) if bb is not None else None
                 for portion, bb in bboxes)

    # Now break each glyph down into tiles
    fmtTile = lambda im: formatTilePlanar(im, fmt)
    portionsT = [
        pilbmp2chr(portion, 8, 32, fmtTile) if portion is not None else []
        for portion in portionsC
    ]
    return portionsT
Exemplo n.º 10
0
def main(argv=None):
    argv = argv or sys.argv
    infilename, outfilename = argv[1:3]
    im = Image.open(infilename)
    tiles = pilbmp2chr(im, formatTile=snesformat)
    utiles, tilemap = flipuniq(tiles)
    assert len(utiles) <= 64
    pbtiles = b"".join(pb16.pb16(b"".join(utiles)))
    tmrows = [bytes(tilemap[i:i + 32]) for i in range(0, len(tilemap), 32)]

    use_utmrows = False
    use_iur = False

    if use_utmrows:
        from uniq import uniq
        utmrows, tmrowmap = uniq(tmrows)
        if len(utmrows) >= 16:
            raise ValueError("%s: too many unique rows: %d > 15" %
                             (infilename, len(utmrows)))
    else:
        utmrows, tmrowmap = tmrows, list(range(len(tmrows)))
    if use_iur:
        from incruniq import iur_encode_tilemap
        iutmrows = iur_encode_tilemap(b''.join(utmrows))
    else:
        iutmrows = b''.join(pb16.pb16(b''.join(utmrows)))

    palette = im.getpalette()[:48]
    snespalette = bytearray()
    for i in range(0, 48, 3):
        r = palette[i] >> 3
        g = palette[i + 1] >> 3
        b = palette[i + 2] >> 3
        bgr = (b << 10) | (g << 5) | r
        snespalette.append(bgr & 0xFF)
        snespalette.append(bgr >> 8)
    print(snespalette.hex())

    out = b"".join(
        (bytes([len(utiles) * 2]), pbtiles,
         bytes([len(utmrows) * 16]) if use_utmrows else b"", iutmrows,
         bytes(tmrowmap) if use_utmrows else b"", snespalette))
    with open(outfilename, "wb") as outfp:
        outfp.write(out)
Exemplo n.º 11
0
def bitmap_to_sav(im, max_tiles=None):
    """Convert a PIL bitmap without remapping the colors."""
    from pilbmp2nes import pilbmp2chr
    from chnutils import dedupe_chr
    (w, h) = im.size
    im = pilbmp2chr(im, 8, 8)

    if max_tiles is not None:
        from jrtilevq import reduce_tiles
        im = reduce_tiles(im, max_tiles)

    namdata = bytearray([0xFF]) * 960
    namdata.extend(bytes(64))
    # If smaller than 16384 pixels, output as a tile sheet
    # with a blank nametable
    if len(im) > 256:
        im, linear_namdata = dedupe_chr(im)
        if len(im) > 256:
            raise IndexError("image has %d distinct tiles, which exceeds 256"
                              % len(im))
        width_in_tiles = w // 8
        height_in_tiles = len(linear_namdata) // width_in_tiles
        topborder = (31 - height_in_tiles) // 2
        leftborder = (32 - width_in_tiles) // 2
        rightborder = 32 - width_in_tiles - leftborder
        offset = topborder * 32 + leftborder
        for i in range(0, len(linear_namdata), width_in_tiles):
            namdata[offset:offset + width_in_tiles] = linear_namdata[i:i + width_in_tiles]
            offset += 32
        assert len(namdata) == 1024

    chrdata = b''.join(im)
    chrpad = b'\xFF' * (6144 - len(chrdata))

    assert len(chrdata) <= 4096
    assert len(chrdata) + len(chrpad) == 6144
    assert len(namdata) == 1024
    sav = b''.join((chrdata, chrpad,
                    namdata, b'\xFF' * 768,
                    default_palette, default_palette, b'\xFF' * 224))
    assert len(sav) == 8192
    return sav
Exemplo n.º 12
0
def bitmap_to_sav(im):
    """Convert a PIL bitmap without remapping the colors."""
    from pilbmp2nes import pilbmp2chr
    from chnutils import dedupe_chr
    (w, h) = im.size
    im = pilbmp2chr(im, 8, 8)

    if len(im) <= 256:
        # smaller than 16384 pixels: output as a tile sheet
        # with a blank nametable
        chrdata = ''.join(im)
        namdata = '\xFF' * 960 + '\x00' * 64
    else:
        from array import array
        im, linear_namdata = dedupe_chr(im)
        if len(im) > 256:
            raise IndexError("image has %d distinct tiles, which exceeds 256" %
                             len(im))
        width_in_tiles = w // 8
        height_in_tiles = len(linear_namdata) // width_in_tiles
        topborder = (31 - height_in_tiles) // 2
        leftborder = (32 - width_in_tiles) // 2
        rightborder = 32 - width_in_tiles - leftborder
        namdata = array('B', '\xFF' * (32 * topborder))
        for i in range(0, len(linear_namdata), width_in_tiles):
            namdata.fromstring('\xFF' * leftborder)
            namdata.extend(linear_namdata[i:i + width_in_tiles])
            namdata.fromstring('\xFF' * rightborder)
        namdata.fromstring('\xFF' * (960 - len(namdata)))
        namdata.fromstring('\x00' * 64)
        namdata = namdata.tostring()
        assert len(namdata) == 1024

    chrdata = ''.join(im)
    chrdata = chrdata + '\xFF' * (4096 - len(chrdata))

    sav = ''.join((chrdata, '\xFF' * 2048, namdata, '\xFF' * 768,
                   default_palette, default_palette, '\xFF' * 224))
    return sav
Exemplo n.º 13
0
def bitmap_to_sav(im):
    """Convert a PIL bitmap without remapping the colors."""
    from pilbmp2nes import pilbmp2chr
    from chnutils import dedupe_chr

    (w, h) = im.size
    im = pilbmp2chr(im, 8, 8)

    if len(im) <= 256:
        # smaller than 16384 pixels: output as a tile sheet
        # with a blank nametable
        chrdata = "".join(im)
        namdata = "\xFF" * 960 + "\x00" * 64
    else:
        from array import array

        im, linear_namdata = dedupe_chr(im)
        if len(im) > 256:
            raise IndexError("image has %d distinct tiles, which exceeds 256" % len(im))
        width_in_tiles = w // 8
        height_in_tiles = len(linear_namdata) // width_in_tiles
        topborder = (31 - height_in_tiles) // 2
        leftborder = (32 - width_in_tiles) // 2
        rightborder = 32 - width_in_tiles - leftborder
        namdata = array("B", "\xFF" * (32 * topborder))
        for i in range(0, len(linear_namdata), width_in_tiles):
            namdata.fromstring("\xFF" * leftborder)
            namdata.extend(linear_namdata[i : i + width_in_tiles])
            namdata.fromstring("\xFF" * rightborder)
        namdata.fromstring("\xFF" * (960 - len(namdata)))
        namdata.fromstring("\x00" * 64)
        namdata = namdata.tostring()
        assert len(namdata) == 1024

    chrdata = "".join(im)
    chrdata = chrdata + "\xFF" * (4096 - len(chrdata))

    sav = "".join((chrdata, "\xFF" * 2048, namdata, "\xFF" * 768, default_palette, default_palette, "\xFF" * 224))
    return sav
Exemplo n.º 14
0
def bitmap_to_sav(im):
    """Convert a PIL bitmap without remapping the colors."""
    from pilbmp2nes import pilbmp2chr
    from chnutils import dedupe_chr
    (w, h) = im.size
    im = pilbmp2chr(im, 8, 8)

    namdata = bytearray([0xFF] * 960)
    namdata.extend([0x00] * 64)
    # If smaller than 16384 pixels, output as a tile sheet
    # with a blank nametable
    if len(im) > 256:
        im, linear_namdata = dedupe_chr(im)
        if len(im) > 256:
            raise IndexError("image has %d distinct tiles, which exceeds 256"
                              % len(im))
        width_in_tiles = w // 8
        height_in_tiles = len(linear_namdata) // width_in_tiles
        topborder = (31 - height_in_tiles) // 2
        leftborder = (32 - width_in_tiles) // 2
        rightborder = 32 - width_in_tiles - leftborder
        offset = topborder * 32 + leftborder
        for i in range(0, len(linear_namdata), width_in_tiles):
            namdata[offset:offset + width_in_tiles] = linear_namdata[i:i + width_in_tiles]
            offset += 32
        assert len(namdata) == 1024

    chrdata = b''.join(im)
    chrpad = b'\xFF' * (6144 - len(chrdata))

    assert len(chrdata) <= 4096
    assert len(chrdata) + len(chrpad) == 6144
    assert len(namdata) == 1024
    sav = b''.join((chrdata, chrpad,
                    namdata, b'\xFF' * 768,
                    default_palette, default_palette, b'\xFF' * 224))
    assert len(sav) == 8192
    return sav
Exemplo n.º 15
0
def main(argv=None):
    global printStats
    import sys

    from pilbmp2nes import formatTilePlanar, pilbmp2chr

    if argv is None:
        argv = sys.argv
        if (argvTestingMode and len(argv) < 2 and sys.stdin.isatty()
                and sys.stdout.isatty()):
            argv.extend(raw_input('args:').split())
    try:
        (infilename, outfilename, maxTiles, useDims, chrCodec, useIndexRLE,
         printStats) = parse_argv(argv)
    except Exception as e:
        sys.stderr.write("%s: %s\n" % (argv[0], str(e)))
        sys.exit(1)

    if printStats:
        print("filename: %s" % infilename, file=sys.stderr)
    im = Image.open(infilename)
    (w, h) = im.size
    if printStats:
        print >> sys.stderr, "size: %dx%d" % im.size
    if w % 8 != 0:
        raise ValueError("image width %d is not a multiple of 8" % w)
    if h % 8 != 0:
        raise ValueError("image height %d is not a multiple of 8" % h)

    ochrdata = pilbmp2chr(im, 8, 8, lambda im: formatTilePlanar(im, 2))
    del im
    (chrdata, ntdata) = dedupe_chr(ochrdata)
    numTiles = len(chrdata)

    if numTiles > maxTiles:
        raise ValueError("%d distinct tiles exceed maximum %d" %
                         (numTiles, maxTiles))

    ochrdata = ''.join(ochrdata)
    chrdata = ''.join(chrdata)
    if printStats:
        print("CHR size before dedupe: %d" % len(ochrdata), file=sys.stderr)
        print("distinct tiles: %d of %d" % (numTiles, len(ntdata)),
              file=sys.stderr)
        print("unpacked CHR size: %d" % len(chrdata), file=sys.stderr)
    if useIndexRLE:
        cntdata = compress_nt(ntdata)
        if printStats:
            print("compressed nametable size: %s" % len(cntdata),
                  file=sys.stderr)
        ntdata = cntdata
    else:
        ntdata = ''.join(chr(x) for x in ntdata)
    if chrCodec == 'packbits':
        from packbits import PackBits
        sz = len(chrdata) % 0x10000
        pchrdata = PackBits(chrdata).flush().tostring()
        pchrdata = bytes([chr(sz >> 8), chr(sz & 0xFF)]) + pchrdata
        if printStats:
            print("packed CHR size: %d" % len(pchrdata), file=sys.stderr)
        chrdata = pchrdata
    elif chrCodec == 'pb8':
        from pb8 import pb8
        sz = len(chrdata) // 16
        pchrdata = pb8(chrdata)
        pchrdata = bytes([sz & 0xFF]) + pchrdata
        if printStats:
            print("packed CHR size: %d" % len(pchrdata), file=sys.stderr)
        chrdata = pchrdata

    if useDims:
        dimsdata = bytes([w // 8, h // 8, numTiles & 0xFF, 0])
    else:
        dimsdata = ''
    outdata = b''.join([dimsdata, ntdata, chrdata])

    # Write output file
    outfp = None
    try:
        if outfilename != '-':
            outfp = open(outfilename, 'wb')
        else:
            outfp = sys.stdout
        outfp.write(outdata)
    finally:
        if outfp and outfilename != '-':
            outfp.close()