| 1 | #!/usr/bin/python |
| 2 | |
| 3 | # This script is a slightly modified version of the original found at |
| 4 | # |
| 5 | # http://wiki.wxwidgets.org/Embedding_PNG_Images-Bin2c_In_Python |
| 6 | # |
| 7 | # without any copyright attribution so it is assumed it can be used under |
| 8 | # wxWindows licence as the rest of the wiki material. |
| 9 | |
| 10 | import sys |
| 11 | import os |
| 12 | import os.path |
| 13 | import re |
| 14 | import array |
| 15 | |
| 16 | USAGE = """Usage: png2c [-s] [file...] |
| 17 | Output input PNG files as C arrays to standard output. Used to embed PNG images |
| 18 | in C code (like XPM but with full alpha channel support). |
| 19 | |
| 20 | -s embed the image size in the image names in generated code.""" |
| 21 | |
| 22 | if len(sys.argv) < 2: |
| 23 | print USAGE |
| 24 | sys.exit(1) |
| 25 | |
| 26 | r = re.compile("^([a-zA-Z._][a-zA-Z._0-9]*)[.][pP][nN][gG]$") |
| 27 | |
| 28 | with_size = 0 |
| 29 | size_suffix = '' |
| 30 | for path in sys.argv[1:]: |
| 31 | if path == '-s': |
| 32 | with_size = 1 |
| 33 | continue |
| 34 | |
| 35 | filename = os.path.basename(path).replace('-','_') |
| 36 | m = r.match(filename) |
| 37 | |
| 38 | # Allow only filenames that make sense as C variable names |
| 39 | if not(m): |
| 40 | print "Skipped file (unsuitable filename): " + filename |
| 41 | continue |
| 42 | |
| 43 | # Read PNG file as character array |
| 44 | bytes = array.array('B', open(path, "rb").read()) |
| 45 | count = len(bytes) |
| 46 | |
| 47 | # Check that it's actually a PNG to avoid problems when loading it |
| 48 | # later. |
| 49 | # |
| 50 | # Each PNG file starts with a 8 byte signature that should be followed |
| 51 | # by IHDR chunk which is always 13 bytes in length so the first 16 |
| 52 | # bytes are fixed (or at least we expect them to be). |
| 53 | if bytes[0:16].tostring() != '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR': |
| 54 | print '"%s" doesn\'t seem to be a valid PNG file.' % filename |
| 55 | continue |
| 56 | |
| 57 | # Try to naively get its size if necessary |
| 58 | if with_size: |
| 59 | def getInt(start): |
| 60 | """ Convert 4 bytes in network byte order to an integer. """ |
| 61 | return 16777216*bytes[start] + \ |
| 62 | 65536*bytes[start+1] + \ |
| 63 | 256*bytes[start+2] + \ |
| 64 | bytes[start+3]; |
| 65 | |
| 66 | size_suffix = "_%dx%d" % (getInt(16), getInt(20)) |
| 67 | |
| 68 | # Create the C header |
| 69 | text = "/* %s - %d bytes */\n" \ |
| 70 | "static const unsigned char %s%s_png[] = {\n" % ( |
| 71 | filename, count, m.group(1), size_suffix) |
| 72 | |
| 73 | # Iterate the characters, we want |
| 74 | # lines like: |
| 75 | # 0x01, 0x02, .... (8 values per line maximum) |
| 76 | i = 0 |
| 77 | count = len(bytes) |
| 78 | for byte in bytes: |
| 79 | # Every new line starts with two whitespaces |
| 80 | if (i % 8) == 0: |
| 81 | text += " " |
| 82 | # Then the hex data (up to 8 values per line) |
| 83 | text += "0x%02x" % (byte) |
| 84 | # Separate all but the last values |
| 85 | if (i % 8) == 7: |
| 86 | text += ',\n' |
| 87 | elif (i + 1) < count: |
| 88 | text += ", " |
| 89 | i += 1 |
| 90 | |
| 91 | # Now conclude the C source |
| 92 | text += "};\n\n" |
| 93 | |
| 94 | print text |