diff --git a/utils/README.md b/utils/README.md new file mode 100644 index 0000000..8c56a9b --- /dev/null +++ b/utils/README.md @@ -0,0 +1,12 @@ +## Utilities + +### decode_cloanto_rom.py + +Turns a Cloanto ROM into a regular Amiga ROM image. Useful e.g. when you have +an emulator/machine that can't read Cloanto ROMs directly. WinUAE has this +built in. + +### png2image.py + +Converts a PNG image into a AmigaOS Image structure that can be used directly +in Intuition programs. diff --git a/utils/png2image.py b/utils/png2image.py new file mode 100755 index 0000000..1de58a0 --- /dev/null +++ b/utils/png2image.py @@ -0,0 +1,75 @@ +#!/usr/bin/python + +""" +For license, see gpl-3.0.txt +""" +from PIL import Image +import argparse +import math +import sys + +def chunks(l, n): + for i in xrange(0, len(l), n): + yield l[i:i+n] + +def color_to_plane_bits(color, depth): + """returns the bits for a given pixel in a list, lowest to highest plane""" + result = [0] * depth + for bit in range(depth): + if color & (1 << bit) != 0: + result[bit] = 1 + return result + +def write_amiga_image(image, outfile): + imdata = im.getdata() + width, height = im.size + colors = [i for i in chunks(map(ord, im.palette.tobytes()), 3)] + depth = int(math.log(len(colors), 2)) + + map_words_per_row = width / 16 + if width % 16 > 0: + map_words_per_row += 1 + + # create the converted planar data + planes = [[0] * (map_words_per_row * height) for _ in range(depth)] + for y in range(height): + x = 0 + while x < width: + # build a word for each plane + for i in range(min(16, width - x)): + # get the palette index for pixel (x + i, y) + color = imdata[y * width + x + i] # color index + planebits = color_to_plane_bits(color, depth) + # now we need to "or" the bits into the words in their respective planes + wordidx = (x + i) / 16 # word number in current row + pos = y * map_words_per_row + wordidx # list index in the plane + for planeidx in range(depth): + if planebits[planeidx]: + planes[planeidx][pos] |= (1 << (15 - (x + i) % 16)) # 1 << ((x + i) % 16) + x += 16 + + outfile.write('#include \n\n') + + outfile.write("/* Ensure that this data is within chip memory or you'll see nothing !!! */\n"); + outfile.write('UWORD imdata[] = {\n') + for plane in planes: + for chunk in chunks(plane, map_words_per_row): + outfile.write(','.join(map(str, chunk))) + outfile.write(',\n') + outfile.write('\n') + outfile.write('};\n\n') + + + planepick = 2 ** depth - 1 # currently we always use all of the planes + outfile.write('struct Image image = {\n') + outfile.write(' 0, 0, %d, %d, %d, imdata,\n' % (width, height, depth)); + outfile.write(' %d, 0, NULL\n' % planepick) # PlanePick, PlaneOnOff + outfile.write('};\n') + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Amiga Image converter') + parser.add_argument('pngfile') + + args = parser.parse_args() + im = Image.open(args.pngfile) + write_amiga_image(im, sys.stdout)