png2c.py 3.1 KB

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