aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorB. Watson <yalhcru@gmail.com>2019-03-30 03:41:23 -0400
committerB. Watson <yalhcru@gmail.com>2019-03-30 03:41:23 -0400
commit41640fe33b90ec675cb86bf8179a44618ee1cfa5 (patch)
treeb569081fdffdeac4bf47ee79d6fc34a904840af5
downloadimg2atari-41640fe33b90ec675cb86bf8179a44618ee1cfa5.tar.gz
initial commitHEADmaster
-rw-r--r--README.txt79
-rwxr-xr-ximg2atari223
-rw-r--r--loader.s114
-rw-r--r--viewer.s35
4 files changed, 451 insertions, 0 deletions
diff --git a/README.txt b/README.txt
new file mode 100644
index 0000000..1344c27
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,79 @@
+img2atari - Quick & dirty image converter for Atari 8-bit computers,
+ using ImageMagick.
+
+Written by B. Watson (yalhcru@gmail.com), released under the
+WTFPL. See http://www.wtfpl.net/txt/copying/ for details.
+
+Purpose:
+
+Convert images in common formats (JPEG, PNG, etc) to black & white Atari
+8-bit image files or executables, in graphics modes 8, 9, or 15.
+
+Requirements:
+
+- Linux or some other UNIX/POSIX like environment (possibly including
+ Mac OSX). You might be able to use Cygwin or MSYS on Windows, or
+ the Ubuntu emulation included in modern Windows (?).
+
+- bash. Easily installed on most Linux and similar OSes these days, if not
+ already part of the OS.
+
+- ImageMagick. At least the convert and composite commands must be found
+ in $PATH.
+
+- Some way to run Atari 8-bit executables, either an emulator or a real
+ Atari with e.g. an SIO2PC cable.
+
+Download:
+
+ wget http://urchlay.naptime.net/repos/img2atari/plain/img2atari
+ chmod +x img2atari
+
+...or:
+
+ git clone http://urchlay.naptime.net/img2atari.git
+
+Installation:
+
+Just copy the img2atari script to some place that's in your $PATH,
+or else run it from the directory you saved it to as "./img2atari".
+
+Usage:
+
+Run "img2atari --help" for full usage information.
+
+Notes:
+
+You don't actually need the loader.s or viewer.s files. These are the
+assembly sources for the object code included in img2atari, and are pretty
+much only useful for informational purposes. You can modify them, but
+there's no easy way to import your modified code into the shell script.
+
+The input file can be in any format ImageMagick can read. This includes at
+least JPEG, PNG, GIF, TIFF, BMP, XPM, EPS... for testing, you can even use
+the ImageMagick built-in images (e.g. "logo:" for the ImageMagick logo).
+For vector formats (e.g. SVG), you'll want to render it to a PNG first.
+For multi-image formats (e.g. animated GIF, PDF), you'll want to extract
+single images and convert those.
+
+Not all images will convert to something that looks OK on the
+Atari. Photographs look OK in GR.9 (though blurry due to the low
+horizontal resolution). Line art looks better in GR.8 or GR.15.
+
+You may have to tweak the image some, before converting it. Images that
+are too dark or too bright will come out with very little detail, so
+try loading the image in an image editor and altering the saturation.
+Also, the conversion to black & white is simplistic. You may get better
+results if you pre-convert to mono or greyscale.
+
+GR.8 images with dithering may show a lot of artifacting on the Atari.
+About the only thing you can do to avoid this is use the chroma/luma
+(s-video) output instead of composite video or RF.
+
+If you get errors from convert and/or composite (e.g. because the input
+file doesn't exist, or isn't recognized by ImageMagick), the output file
+will be useless and should be deleted.
+
+The 'loader' included with the -x option uses the OS to set up the
+graphics mode, so custom resolutions (wide/narrow playfield, nonstandard
+number of scanlines) are not supported.
diff --git a/img2atari b/img2atari
new file mode 100755
index 0000000..d52c8e2
--- /dev/null
+++ b/img2atari
@@ -0,0 +1,223 @@
+#!/usr/bin/env bash
+
+# This really is a bash script. It also seems to work in zsh, but not
+# ksh or dash. This is not a bug.
+
+SELF="$( basename $0 )"
+
+help() {
+ cat <<EOF
+$SELF - Quick & dirty image converter for Atari 8-bit computers,
+ using ImageMagick.
+
+Written by B. Watson (yalhcru@gmail.com), released under the
+WTFPL. See http://www.wtfpl.net/txt/copying/ for details.
+
+Usage: $SELF [options] [inputfile] [outputfile]
+
+Options:
+-g <mode> Graphics mode for outputfile (8, 9, or 15, default 9)
+-f <color> Color register value for GR.8 foreground (default 0x0c)
+-b <color> Color register value for GR.8 background (default 0x00)
+-x Create standalone executable with loader and viewer
+-X Create executable with loader only as an init segment
+-a <addr> Create binary load data file, load image at <addr>
+-l <addr> Load address for -x/-X loader (default 0x0400). Give
+ address in either decimal or hex with 0x prefix.
+-d Dither. May improve results, or ruin them (YMMV). Doesn't
+ actually seem to have any visible effect.
+-r <byte> For use with -x/-X: set RAMTOP. Default 192 (>=48K Atari
+ with no cartridge or BASIC). Use 160 if BASIC will be enabled,
+ or 64 for unexpanded 400 or 600XL, etc.
+
+To write to standard output, use - as the outputfile. Reading from
+standard input is not supported.
+
+The image is scaled to fit in the desired graphics mode (with aspect
+ratio preserved) and converted to greyscale: 4 bits for -g 9, 2 bits
+for -g 15, and 1 bit (true monochrome) for -g 8.
+
+With -g 15, the loader will set the color registers to \$00 \$04 \$08
+\$0C. For raw images, you'll want to set them in whatever code you write
+that uses the raw file.
+
+Output file format depends on options given:
+
+- With no -a/-x/-X options, the output is a raw screen memory image.
+ With -g 8 or 9, this is the same as an Atari .GR8 or .GR9 file. With
+ -g 15, it's similar to a Koala .pic file, except the color registers
+ aren't saved.
+
+- With -a, the output is an Atari binary load file that loads the
+ image data at the given address, but includes no executable code. By
+ itself, this isn't very useful, but it could be used as part of a
+ multi-segment executable, or with the BLOAD command in Turbo BASIC.
+
+- With -x, the output is a standalone executable that loads and displays
+ the image in the given graphics mode, then waits for the user to press
+ a key, then exits to DOS.
+
+- With -X, the output is a binary load file that displays the image, but
+ doesn't include the "wait for keypress" code. This would be useful as
+ part of a multi-segment executable.
+EOF
+}
+
+#-n BROKEN! Narrow GTIA mode (256x192 for GR.8, 128x192 for GR.15)
+
+die() {
+ echo "$SELF: $@" 1>&2
+ exit 1
+}
+
+printbyte() {
+ printf -v tmpbyte "%02x" "$1"
+ LANG=C echo -n -e "\x$tmpbyte"
+}
+
+printword() {
+ printbyte $(( $1 % 256 ))
+ printbyte $(( $1 / 256 ))
+}
+
+printbytes() {
+ for i in "$@"; do printbyte 0x$i; done
+}
+
+GRMODE=9
+DITHER="+dither"
+RAMTOP=192
+LOADERADDR=1024
+SDMCTL=0x22
+
+if [ "$#" = "0" ]; then
+ help
+ exit 0
+fi
+
+while [ "$1" != "" ]; do
+ case "$1" in
+ "--help"|"-help"|"-h"|"-?") help ; exit 0 ;;
+ "-g") GRMODE="$2" ; shift ;;
+ "-f") FGCOLOR="$2" ; shift ;;
+ "-b") BGCOLOR="$2" ; shift ;;
+ "-x") LOADER=1; VIEWER=1 ;;
+ "-X") LOADER=1; VIEWER=0 ;;
+ "-a") IMGSTART="$2" ; shift ;;
+ "-l") LOADERADDR="$2" ; shift ;;
+ #"-n") NARROW=1; SDMCTL=0x21 ;;
+ "-n") die "narrow mode not yet supported" ;;
+ "-d") DITHER="" ;;
+ "-r") RAMTOP="$2" ; shift ;;
+ -?*) die "invalid option '$1'" ;;
+ *)
+ if [ "$INFILE" = "" ]; then
+ INFILE="$1"
+ elif [ "$OUTFILE" = "" ]; then
+ OUTFILE="$1"
+ else
+ die "extra junk on the command line: '$1'"
+ fi
+ ;;
+ esac
+ shift
+done
+
+type -p convert > /dev/null && type -p composite > /dev/null || \
+ die "Can't find 'convert' and 'composite' in \$PATH. Install ImageMagick?"
+
+[ "$INFILE" = "" ] && die "No input filename given"
+[ "$INFILE" = "-" ] && die "Reading stdin not supported"
+[ "$OUTFILE" = "" ] && die "No output filename given (use - for stdout)"
+
+# ASPECT pretends GR.8 pixels are square, GR.15 are 2x1 rectangles,
+# and GR.9 are 4x1. This isn't entirely true...
+case "$GRMODE" in
+ 8) W=320; H=192; COLORS=2; DEPTH=1; ASPECT=100; FGCOLOR=${FGCOLOR:-0x0c}; BGCOLOR=${BGCOLOR:-0x00} ;;
+ 15) W=160; H=192; COLORS=4; DEPTH=2; ASPECT=50 ;;
+ 9) W=80; H=192; COLORS=16; DEPTH=4; ASPECT=25 ;;
+ *) die "invalid graphics mode '$GRMODE' (only 8 and 15 supported)" ;;
+esac
+
+#[ "$NARROW" = "1" ] && W=$(( $W / 40 * 32 ))
+
+[ "$OUTFILE" = "" ] && OUTFILE="-"
+[ "$OUTFILE" != "-" ] && exec > $OUTFILE
+
+if [ "$LOADER" = "1" ]; then
+ if [ "$IMGSTART" != "" ]; then
+ die "-a option can't be combined with -x/-X"
+ fi
+
+ LOADEREND=$(( $LOADERADDR + 113 ))
+ IMGSTART=$(( $RAMTOP * 256 - 7856 ))
+
+ # xex header
+ printword 0xffff
+ printword $LOADERADDR
+ printword $LOADEREND
+
+ # data table (see loader.s)
+ printbyte $RAMTOP
+ printbyte $GRMODE
+ printbyte 0x04
+ printbyte ${FGCOLOR:-0x08}
+ printbyte ${BGCOLOR:-0x0c}
+ printbyte 0x00
+ printbyte 0x00
+ printbyte $SDMCTL
+
+ # code (see loader.s)
+ printbytes 78 a9 00 8d 0e d4 a9 60 85 d4 20 d4 00 ba ca bd 00 01
+ printbytes 38 e9 14 85 d4 bd 01 01 e9 00 85 d5 58 a9 40 8d
+ printbytes 0e d4 a0 00 b1 d4 85 6a a2 60 a9 0c 9d 42 03 20
+ printbytes 56 e4 a2 60 a9 0c 9d 4a 03 a0 01 b1 d4 9d 4b 03
+ printbytes a9 03 9d 42 03 a9 53 85 d6 a9 d6 9d 44 03 a9 00
+ printbytes 9d 45 03 20 56 e4 a0 02 b1 d4 99 c2 02 c8 c0 07
+ printbytes d0 f6 b1 d4 8d 2f 02 60
+
+ # INITAD segment
+ printbytes e2 02 e3 02
+ printword $(( LOADERADDR + 8 ))
+
+ # Narrow display needs 2nd DL LMS adjusted
+## if [ "$NARROW" = 1 ]; then
+## printword 0xffff
+## printword $(( IMGSTART - 182 ))
+## printword $(( IMGSTART - 181 ))
+## printword $(( IMGSTART + 32 * 94 ))
+## fi
+fi
+
+if [ "$IMGSTART" != "" ]; then
+ IMGBYTES=$(( $W * $H / 8 * $DEPTH ))
+ IMGEND=$(( $IMGSTART + $IMGBYTES - 1 ))
+ printword 0xffff
+ printword $IMGSTART
+ printword $IMGEND
+fi
+
+convert "$INFILE" $DITHER -scale ${ASPECT}%x100%\! -colorspace gray -scale ${W}x${H} -depth $DEPTH -colors $COLORS gif:- | \
+composite gif:- -size ${W}x${H} -depth $DEPTH -colors $COLORS -gravity center xc:black gray:-
+
+if [ "$VIEWER" = 1 ]; then
+ LOADEREND=$(( $LOADERADDR + 12 ))
+
+ # xex header
+ printword 0xffff
+ printword $LOADERADDR
+ printword $LOADEREND
+
+ # code (see viewer.s)
+ printbytes a9 ff 8d fc 02 ad fc 02 c9 ff f0 f9 60
+
+ # RUNAD segment
+ printbytes e0 02 e1 02
+ printword $LOADERADDR
+fi
+
+exit 0
+
+# dump pixels' RGB values as text:
+# convert in.png +dither -scale 320x192 -depth 2 -colors 4 -remap a8_ntsc_palette.png txt:- |sed 's,.*#\([0-9A-F]\{6\}\).*,\1,'|sort -u
+# could someday be used to support color images in GR.15, or something like APAC.
diff --git a/loader.s b/loader.s
new file mode 100644
index 0000000..3b78fbd
--- /dev/null
+++ b/loader.s
@@ -0,0 +1,114 @@
+; Use CIO to set up S: as GR.8 or GR.15
+; Relocatable code.
+; Assemble with:
+; cl65 -t none -o loader.xex loader.s
+
+ .include "atari.inc"
+
+dataptr = FR0
+tmp = FR0+2
+
+start = $0400
+
+; segment header
+ .org start-6
+ .word $FFFF
+ .word start
+ .word endmain-1
+
+ .org start
+ .byte $c0 ; default RAMTOP
+ .byte $0f ; GR. mode (8 or 15)
+ .byte $04 ; COLOR0 (01 pixels in GR.15)
+ .byte $08 ; COLOR1 (10 pixels in GR.15, 1 pixels in GR.8)
+ .byte $0c ; COLOR2 (11 pixels in GR.15, 0 pixels in GR.8)
+ .byte $00 ; COLOR3 (unused)
+ .byte $00 ; COLOR4 (00 pixels in GR.15, border in GR.8)
+ .byte $22 ; SDMCTL ($21 for narrow, $22 for normal)
+
+main:
+; find our datablock's start address. this song and dance routine
+; allows us to be fully relocatable, and have all the data in a
+; single block (easily modified by the shell script that uses this).
+
+ sei ; disable interrupts so they don't clobber the stack
+ lda #$00
+ sta NMIEN
+ lda #$60 ; RTS opcode
+ sta dataptr
+ jsr dataptr
+ret: ; here is where the RTS returns to
+
+; address is now in the stack area, fix it up and save it
+ tsx
+ dex
+ lda $100,x ; lo byte
+ sec
+ sbc #ret-start-1
+ sta dataptr
+ lda $101,x ; hi byte
+ sbc #0
+ sta dataptr+1 ; $d4/$d5 is now a pointer to 'start'
+
+ cli ; re-enable interrupts
+ lda #$40
+ sta NMIEN
+
+; set RAMTOP
+ ldy #0
+ lda (dataptr),y
+ sta RAMTOP
+
+; close device #6
+ ldx #$60
+ lda #CLOSE
+ sta ICCOM,x
+ jsr CIOV
+
+; open device #6 (GRAPHICS command basically)
+ ldx #$60
+ lda #$0c ; read/write, no +16 or +32
+ sta ICAX1,x
+ ldy #$01
+ lda (dataptr),y
+ sta ICAX2,x ; just the mode (8 or 16)
+ lda #OPEN
+ sta ICCOM,x
+ lda #'S'
+ sta tmp
+ lda #<tmp
+ sta ICBAL,x
+ lda #>tmp
+ sta ICBAH,x
+ jsr CIOV
+
+; set up color regs
+ ldy #$02
+cloop:
+ lda (dataptr),y
+ sta COLOR0-2,y
+ iny
+ cpy #$07
+ bne cloop
+
+; set up display width
+ lda (dataptr),y
+ sta SDMCTL
+
+ rts
+;;; put some stuff in screen RAM so we can see it
+;; lda #$ff
+;; sta $a150
+;; lda #$aa
+;; sta $a151
+;; lda #$55
+;; sta $a152
+;;hang: jmp hang
+
+endmain:
+
+; segment header
+ .word INITAD
+ .word INITAD+1
+ .word main
+
diff --git a/viewer.s b/viewer.s
new file mode 100644
index 0000000..8479cc4
--- /dev/null
+++ b/viewer.s
@@ -0,0 +1,35 @@
+; Wait for keypress, then exit
+; Relocatable code.
+; Assemble with:
+; cl65 -t none -o viewer.xex viewer.s
+
+ .include "atari.inc"
+
+dataptr = FR0
+tmp = FR0+2
+
+start = $0400
+
+; segment header
+ .org start-6
+ .word $FFFF
+ .word start
+ .word endmain-1
+
+ .org start
+main:
+ lda #$ff
+ sta 764
+loop:
+ lda 764
+ cmp #$ff
+ beq loop
+
+ rts
+endmain:
+
+; segment header
+ .word RUNAD
+ .word RUNAD+1
+ .word main
+