Added compatibility with Linux and Windows in addition to OSX.

Added ability for Linux and Windows to run this script. Now everyone can use this!
Added friendly and instructive error message for when pypng is not installed.
Fixed bugs that prevented the proper printing output.
Fixed the try/except/finally's to be try/except's.
Fixed inconsistent space and tab indentation which will fail with Python 3.
Fixed sys.exit(0) to exit with code of 1, which indicates an error to the shell.
Added the shebang to the first line so that the script can be run on its own.
Fixed the ImageMagick command line to be more compatible running under Windows shell.
This commit is contained in:
Michael Devendra 2015-08-14 00:25:12 -07:00
parent c0f6bbea83
commit f6bfab3c74
1 changed files with 70 additions and 36 deletions

View File

@ -1,67 +1,71 @@
# KansasFest 2015 #! /usr/bin/env python
# HackFest Entry: Disk Images Images
# By Charles Mangin
# @RetroConnector
# requires ImageMagick: http://www.imagemagick.org/ """
# and python PNG module: https://pypi.python.org/pypi/pypng KansasFest 2015
HackFest Entry: Disk Images Images
By Charles Mangin
@RetroConnector
requires ImageMagick: http://www.imagemagick.org/
and python PNG module: https://pypi.python.org/pypi/pypng
"""
import os,sys # filesystem functions import os,sys # filesystem functions
import png # PNG image library
try: try:
INPUTFILE = sys.argv[1] # what DSK file to parse import png # PNG image library
except:
print("\n\n" + sys.argv[0] + " requires the Python PNG module\n\n Download from https://pypi.python.org/pypi/pypng \n Or type in shell: pip install pypng\n\n")
sys.exit(1) # exit on exception - no library installed
try:
INPUTFILE = sys.argv[1] # what DSK file to parse
DSK = open(INPUTFILE, "rb") # open the DSK file for reading DSK = open(INPUTFILE, "rb") # open the DSK file for reading
except: except:
print("\n\nUsage: python [filename]\n\n [filename] should be a DSK file of 143kb.\n\n") print("\n\nUsage: python "+ sys.argv[0] +" [filename]\n\n [filename] should be a .DSK file of 143kb.\n")
sys.exit(0) # exit on exception - no file chosen sys.exit(1) # exit on exception - no file chosen
finally:
PNG = open("DiskImageTEMP.png", "wb") # open a PNG for writing TEMPFILENAME = "DiskImageTEMP.png"
PNG = open(TEMPFILENAME, "wb") # open a PNG for writing
# The point: Make a PNG image from the data on a floppy disk image. # The point: Make a PNG image from the data on a floppy disk image.
# 35 tracks, each with 16 sectors of 256 bytes each, for a total of 143,360 bytes # 35 tracks, each with 16 sectors of 256 bytes each, for a total of 143,360 bytes
# so 35 lines of 4096 px. # so 35 lines of 4096 px.
# new, empty arrays # new, empty arrays
BYTES = [] BYTES = []
PIXELS = [] PIXELS = []
try: try:
byte = DSK.read(1) # read a byte byte = DSK.read(1) # read a byte
while byte !="": # while the file still has bytes in it while byte != "": # while the file still has bytes in it
byte = DSK.read(1) byte = DSK.read(1)
if len(byte) > 0: # the last byte, for whatever reason, is length 0. Bah. if len(byte) > 0: # the last byte, for whatever reason, is length 0. Bah.
BYTES.append(ord(byte)) # append the number representing the byte (0-255) to the BYTES array BYTES.append(ord(byte)) # append the number representing the byte (0-255) to the BYTES array
except: except:
print("\n\nOops. Is " + INPUTFILE + " a DSK file of 143kb?\n\n") print("\n\nOops. Is " + INPUTFILE + " a DSK file of 143kb?\n\n")
sys.exit(0) # exit on exception - file is empty, etc sys.exit(1) # exit on exception - file is empty, etc
finally:
sys.stdout.write("\r Starting.\n\n")
for TRACK in range(0,35,1): # for each of the 35 tracks print("\n Starting.\n")
LINE=[] # start a new line of pixels
for SECTOR in range(0,4096,1): # write the bytes for the sectors in that track to the line array
offset = (SECTOR * TRACK) + SECTOR
LINE.append(BYTES[(SECTOR * TRACK) + SECTOR])
sys.stdout.write("\r Track: " + str(TRACK)) for TRACK in range(0,35,1): # for each of the 35 tracks
sys.stdout.flush() LINE=[] # start a new line of pixels
PIXELS.append(LINE) # add the array of pixels to the array of arrays for SECTOR in range(0,4096,1): # write the bytes for the sectors in that track to the line array
offset = (SECTOR * TRACK) + SECTOR
LINE.append(BYTES[(SECTOR * TRACK) + SECTOR])
sys.stdout.write("\n\n\r Done.\n\n") print(" Track: " + str(TRACK))
sys.stdout.flush() PIXELS.append(LINE) # add the array of pixels to the array of arrays
print("\n Done.\n")
# write to the PNG file # write to the PNG file
w = png.Writer(4096,35, greyscale=True, bitdepth=8) w = png.Writer(4096,35, greyscale=True, bitdepth=8)
w.write(PNG, PIXELS) # each number in the array becomes a pixel in the image. each array becomes a line. w.write(PNG, PIXELS) # each number in the array becomes a pixel in the image. each array becomes a line.
sys.stdout.write("\n\n\r Writing to disk. Chunka-chunk-cka. Whirr.\n\n") print(" Writing to disk. Chunka-chunk-cka. Whirr...\n")
sys.stdout.flush()
DSK.close() # done with these files. close them. DSK.close() # done with these files. close them.
@ -71,8 +75,38 @@ PNG.close()
OUTPUTFILE = os.path.join(INPUTFILE + ".png") OUTPUTFILE = os.path.join(INPUTFILE + ".png")
# set a destination file same as DSK, but with PNG extension # set a destination file same as DSK, but with PNG extension
os.system('convert DiskImageTEMP.png -matte -virtual-pixel transparent -resize 1024x1024! -rotate 90 -distort Polar \'512 110 512,512 -180,180\' ' + OUTPUTFILE) os.system('convert '+TEMPFILENAME+' -matte -virtual-pixel transparent -resize 1024x1024! -rotate 90 -distort Polar "512 110 512,512 -180,180" "'+OUTPUTFILE+'"')
# convert the 4096x35px image to a square, rotate, then rotate around an axis. # Using ImageMagick, convert the 4096x35px image to a square, rotate, then rotate around an axis.
# NOTE: Windows command line needs to have Polar coordinates enquoted with " not '
# NOTE: Windows has a native command called convert which does something very different
# from ImageMagick's convert command, so obviously this will fail if IM is not installed
os.system('open ' + OUTPUTFILE) # opens the resulting image in the default image viewer (Preview.app) if 'win32' in sys.platform:
# Because the Windows "start" commandline command cannot take an enquoted file or pathname,
# which is necessary if the path has spaces, we have to obtain the "short" version of
# the file/path in the 8.3 format. There is no Python library to do this for us.
# Said another way: Windows is broken in that enquoting a file argument after their start
# command causes it to open a blank terminal. Boo!
# But we do this *after* the ImageMagick convert process above, because that will take an
# enquoted file just fine.
from ctypes import windll, create_unicode_buffer, sizeof
buf = create_unicode_buffer( 512 )
if windll.kernel32.GetShortPathNameW( unicode(OUTPUTFILE), buf, sizeof(buf) ):
OUTPUTFILE = buf.value
else:
# Otherwise we enquote the output file becuase it may have spaces
OUTPUTFILE = '"' + OUTPUTFILE + '"'
platform_commands = {
'darwin' : 'open', # opens the resulting image in the default Mac image viewer (Preview.app)
'linux' : 'xdg-open', # opens the resulting image in the default Linux image viewer (mime-determined); Python 2: 'linux2', Python 3: 'linux'
'win32' : 'start' # opens the resulting image in the default Windows image viewer (Windows Photo Viewer, or...?)
}
# Open the .PNG in the default image viewer
for platform,command in platform_commands.items():
if platform in sys.platform:
os.system(command + ' ' + OUTPUTFILE)
break
else:
print(" Your file is ready to view: " + OUTPUTFILE)