From c4edc98b519b176594b151f3ad49dc009a098c3e Mon Sep 17 00:00:00 2001 From: Charles Mangin Date: Fri, 5 Mar 2021 09:58:07 -0500 Subject: [PATCH] Add files via upload --- DSK-Image.py | 147 +++++++++++++++++++++++++++++++++++++++++++++++++++ readme.md | 47 ++++++++++++++++ 2 files changed, 194 insertions(+) create mode 100644 DSK-Image.py create mode 100644 readme.md diff --git a/DSK-Image.py b/DSK-Image.py new file mode 100644 index 0000000..e592f18 --- /dev/null +++ b/DSK-Image.py @@ -0,0 +1,147 @@ +#! /usr/bin/env python + +""" + 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 subprocess + + +try: + 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 +except: + print("\n\nUsage: python "+ sys.argv[0] +" [filename]\n\n [filename] should be a .DSK file of 143kb.\n") + sys.exit(1) # exit on exception - no file chosen + + +print("Checking " + INPUTFILE + "...\n") + +# to do: check for 140k 5.25'' disks vs 400k/800k 3.5'' and adjust accordingly + +if (os.path.getsize(INPUTFILE)) != 143360: # check file size. for 5.25'', it needs to be 143k + print("\n\nOops. Is " + INPUTFILE + " a DSK file of 143kb?\n\n") + sys.exit(1) # exit on exception - file is empty, etc + + # The point: Make a PNG image from the data on a floppy disk image. + # 5.15'' disks have 35 tracks, each with 16 sectors of 256 bytes each, for a total of 143,360 bytes + # so 35 lines of 4096 px. +TRACKS = 35 +SECTORS = 16 +BYTESPERSECTOR = 256 + +TEMPFILENAME = "DiskImageTEMP.png" +PNG = open("DiskImageTEMP.png", "wb") # open a PNG for writing + + + # new, empty arrays +BYTES = [] +PIXELS = [] + +try: + byte = DSK.read(1) # read a byte +<<<<<<< HEAD + while byte != "": # while the file still has bytes in it + byte = DSK.read(1) + 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 +======= + while byte !="": # while the file still has bytes in it + BYTES.append(ord(byte)) # append the number representing the byte (0-255) to the BYTES array + byte = DSK.read(1) + +>>>>>>> master +except: + print("\n\nOops. Is " + INPUTFILE + " a DSK file of 143kb?\n\n") + sys.exit(1) # exit on exception - file is empty, etc + + +print("\n Starting.\n") + +<<<<<<< HEAD +for TRACK in range(0,TRACKS,1): # for each of the 35 tracks + LINE=[] # start a new line of pixels + for SECTOR in range(0,SECTORS*BYTESPERSECTOR,1): # write the bytes for the sectors in that track to the line array + offset = (SECTOR * TRACK) + SECTOR + LINE.append(BYTES[(SECTOR * TRACK) + SECTOR]) +======= + for TRACK in range(TRACKS): # for each of the 35 tracks + LINE=[] # start a new line of pixels + for SECTOR in range(SECTORS*BYTESPERSECTOR): # write the bytes for the sectors in that track to the line array + LINE.append(BYTES[(SECTORS*BYTESPERSECTOR * TRACK) + SECTOR]) +>>>>>>> master + + print(" Track: " + str(TRACK)) + PIXELS.append(LINE) # add the array of pixels to the array of arrays + +print("\n Done.\n") + + # write to the PNG file +w = png.Writer(SECTORS*BYTESPERSECTOR,TRACKS, greyscale=True, bitdepth=8) +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 bytes to disk. Chunka-chunka-chunk. Whirr.\n\n") +sys.stdout.flush() + +DSK.close() # done with these files. close them. +PNG.close() + + +OUTPUTFILE = os.path.join(INPUTFILE + ".png") + # set a destination file same as DSK, but with PNG extension + + + +try: + subprocess.call(['convert', 'DiskImageTEMP.png', '-scale', '100%x300%', '-resize', '3072x!', '(', '-size', '3072x115', 'pattern:horizontal3', '-negate', '-alpha', 'copy', '-fx', '#000', ')', '-composite', '-virtual-pixel', 'HorizontalTile', '-flip', '+distort', 'Polar', '1024 220', '-resize', '50%x50%', OUTPUTFILE]) + + # convert the 4096x35px image to a square, rotate, then rotate around an axis. +except OSError: + print("\n\nOops. This script requires ImageMagick: http://www.imagemagick.org/") + sys.exit(1) # exit on exception - needs imagemagick installed + + + +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) diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..4d9c5d3 --- /dev/null +++ b/readme.md @@ -0,0 +1,47 @@ +At 2015’s KansasFest [http://kansasfest.org], I had the idea to convert Apple II disk images, of the kind used to run in an emulator, to actual images, of the kind you can view with your eyeballs. I was using the DSK format, which is one of several common image formats. + +The resulting images were illuminating and pretty, but flawed. DSK, being abstracted from the original bits, no longer represents actual bytes on disk. Plus, it doesn’t work reliably for copy-protected disks. I wanted to ‘see’ the bits. The closest representation we can get is what’s called EDD, named for the Essential Disk Duplicator. I won’t go into the details, but it’s a hardware method of imaging a floppy that captures bytes before they are interpreted by the Apple II, and is more of a one-to-one to bytes on disk. + +So, I recently polished off the original script, dug a little more into imagemagick, and learned about the EDD format itself. + +The resulting images are much more detailed and nuanced. A few samples are included in the Images directory. + +And here’s all it takes. One line of imagemagick command line arguments: + + filename=EDD-FILENAME;convert -depth 8 -size 16384x141 gray:"$filename" -crop '6554x141!+0+0' -scale 100%x800% -flip -virtual-pixel 'transparent' +distort Polar '1024 256' "$filename".png + +I’ll break it down: + + filename=EDD-FILENAME; + +your EDD file name goes here. + + convert -depth 8 -size 16384×141 gray:”$filename” + +“convert” is the imagemagick command. This tells it to create an 8 bits-per-pixel greyscale image, based on the bytes in the EDD file defined above. The size is based on the EDD format, which stores 2.5 copies of each disk track in a bistream 16384 bytes long. There are 141 quarter-tracks in the EDD file, so that is the vertical resolution. + + -crop ‘6554×141!+0+0’ + +crops the resulting image down to 6554 bytes wide (1x track instead of 2.5) starting at the top left corner. + + -scale 100%x800% -flip + +stretches the vertical resolution by 800% and flips it vertically. This is optional, but if you stop here, the resulting image is easier to “read” the tracks. + +The resulting image at this step looks like this. + + -virtual-pixel ‘transparent’ +distort Polar ‘1024 256’ + +distorts the rectangular image around a circle 1024 pixels in diameter, with a hole 256 pixels in the middle. This roughly represents the floppy disk media. The background, instead of consisting of stretched out pixels from the edge, is transparent. + + “$filename”.png + +Finally, write the result to a PNG file with the same filename as your EDD, with PNG extension. + +*Caveats:* + +The EDD file contains “about” 2.5 rotations of each track. The variability of hardware and each disk means the track length in bytes isn’t precisely 6554 bytes. In some examples, you can see the “seam” where the track length isn’t exactly 1. + +At 8 bits-per-pixel, the image is more visually appealing than a true representation of the bits. Fiddling with the values can get you a 1 bit-per-pixel version, as well as higher resolution. The size of the above images is chosen for portability, not any specific function or utility. + +The EDD files I’m using are from Project Applesauce by John Keoni Morris. His hardware, unlike the EDD card and its clones, synchronizes the tracks of the resulting EDD, and so are going to have better/different properties to other typical EDD files found online.