#!/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 < Graphics mode for outputfile (8, 9, or 15, default 9) -f Color register value for GR.8 foreground (default 0x0c) -b 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 Create binary load data file, load image at -l 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 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.