[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Screendump to MacPaint file for MiNT 1.10 + Psigintr
Well, I needed something to dump a screen to a MacPaint file, and I couldn't
find anything like that, let alone working under MiNT, thus this program.
The screen rotation code is pretty slow; I'm working on a more efficient one
but it works, so what the heck.
Hope someone else finds this useful... -- Howard
/*
* scrdump - Dump a monochrome screen in MacPaint format. Requires MiNT 1.10
* plus Psigintr extension. I wrote this program because I've seen no other
* code that will dump a screen to a file when running under MiNT.
*
* The program doesn't put itself into the background, but it ought to.
* Dump files are named "ScreenXX.MAC" with two hex digits "XX". The program
* exits after dumping 256 images. If the environment variable SCRDUMPS exists
* and is set to a GEMDOS-format pathname, dumps will be created in that
* directory, otherwise they will be in the current working directory.
*
* The MacPaint format isn't exactly the greatest format in the world. It's
* a fixed size, 576 horizontal by 720 vertical. The only reason I used it
* is because I needed to get some screen dumps to a doc-writer who was using
* a Mac, and this is the simplest Mac format I had docs for. To get a better
* fit, I rotate the ST screen 90 degrees before dumping it to disk. For
* screens larger than 720x576, only the upper left corner gets dumped.
*
* Not the best-written stuff in the world, but it works...
*
* -- Howard Chu, howard@lloyd.com 4-5-94
* (also at hyc@hanauma.jpl.nasa.gov, but phasing that out.)
*/
#include <mintbind.h>
#include <unistd.h>
#include <signal.h>
#include <linea.h>
int quit;
void sigit (int sig) {
if (sig != SIGHUP)
quit = 1;
}
/*
* Once again, a strange problem - how do you get a signal from an interrupt-
* time routine into a MiNT process. Using Psigintr directly doesn't work here
* because the ALT-Help vector isn't at a long-word aligned address, and it's
* invoked as a subroutine, not an exception. Perhaps Psigintr should be
* changed to take an address instead of a vector number, with another argument
* telling whether to return with RTE or RTS... ?
*
* Anyway, my solution here is to set the ALT-Help vector to point to a
* routine that invokes an unused trap. Psigintr is called with that trap
* vector, and so the desired signal gets delivered... What a kludge.
*/
#define Prt_cnt *(short *)0x4eeL
#define Scr_dump *(long *)0x502L
#define TRAP0VEC 0x20
void trapper () {
if (Prt_cnt == 0)
Prt_cnt = -1;
__asm__("trap #0");
}
long oldprt;
void installer () {
oldprt = Scr_dump;
Scr_dump = (long)trapper;
}
void remover() {
Scr_dump = oldprt;
}
const char digx[]="0123456789ABCDEF";
char file[]="Screen00.MAC";
/* MacPaint dimensions */
#define M_X_MAX 576
#define M_Y_MAX 720
#define MAC_BUF ((M_X_MAX*M_Y_MAX>>3)+512)
main() {
int i, j;
int snum;
int xmax, ymax; /* max dimension, unrotated */
int xlen;
int fd;
char *scr;
char *wd, *pbuf;
char *pt1, *pt2, *pt3, *pt4;
char c, m1, m2;
/* Go to specified dump directory */
wd = (char *)getenv("SCRDUMPS");
if (wd) {
if (wd[1] == ':') {
Dsetdrv((wd[0] & 0x1f)-1);
wd += 2;
}
Dsetpath(wd);
}
scr = (char *)Logbase();
/* Yeah, I know Line-A isn't supposed to be used any more, but it
* still works on TT and Falcon, and there's no where else to find
* the Bytes_Per_Line value...
*/
linea0();
xmax = V_X_MAX;
if (xmax > M_Y_MAX)
xmax = M_Y_MAX;
ymax = V_Y_MAX;
if (ymax > M_X_MAX)
ymax = M_X_MAX;
xlen = V_BYTES_LIN;
wd = malloc(MAC_BUF); /* MacPaint rez + header */
bzero(wd, MAC_BUF); /* zero the buffer */
wd += 512; /* Skip over the header */
pbuf = malloc((ymax>>3)+1); /* 1 PackBits line */
#if BORDERS==1
/* Draw 2-pixel borders if image is smaller than MacPaint size */
if (ymax < M_X_MAX) {
pt1 = wd + (ymax>>3);
j = xmax+2;
if (j > M_Y_MAX) j = M_Y_MAX;
for (i=0; i<j; i++) {
*pt1 = 0xc0;
pt1 += (M_X_MAX>>3);
}
}
if (xmax < M_Y_MAX-1) {
pt1 = wd + xmax*(M_X_MAX>>3);
for (i=0; i<ymax>>3; i++)
*pt1++ = 0xff;
pt1 += (M_X_MAX-ymax) >> 3;
for (i=0; i<ymax>>3; i++)
*pt1++ = 0xff;
}
#endif
/* Use trap 0 vector to signal us */
signal(SIGHUP, sigit);
signal(SIGINT, sigit);
signal(SIGQUIT, sigit);
signal(SIGTERM, sigit);
Psigintr(TRAP0VEC, SIGHUP);
Supexec(installer);
for(snum=0;snum<256;snum++) {
/* Set file name */
file[7] = digx[snum & 0x0f];
file[6] = digx[snum >> 4];
/* Wait for ALT-Help signal */
Pause();
if (quit)
break;
/* Open output file, write header */
fd = Fcreate(file, 0);
if (fd < 0)
continue;
Fwrite(fd, 512, wd-512);
/* Rotate image 90 degrees */
pt1=scr + (xmax>>3)-1; /* Far right src column */
pt2=wd + ((M_X_MAX*(xmax-1)+ymax)>>3)-1;
/* lower right corner */
for (i=0, m1=1; i<xmax; i++) {
pt3 = pt1; /* input */
m2 = 1;
for (j=0, c=0; j<ymax; j++) {
if (*pt3 & m1)
c |= m2;
pt3 += xlen;
if (m2 < 0) {
m2 = 1;
*pt2-- = c;
c = 0;
} else {
m2 += m2;
}
}
pt2 -= ((M_X_MAX-ymax)>>3);
if (m1 < 0) { /* signed char */
m1 = 1;
pt1--;
} else {
m1 += m1;
}
}
/* Write output in PackBits format */
pt1 = wd;
#if PACKBITS==1
for (i=0; i<M_Y_MAX; i++) { /* For each line */
m1 = 0; /* No repeats */
m2 = *pt1+1; /* Previous char */
pt3 = pt1; /* beginning of literal */
pt4 = 0; /* beginning of run */
pt2 = pbuf;
for (j=0; j<M_X_MAX>>3; j++) {
if (*pt1 == m2) {
if (pt4) { /* Accumulate repeats */
m1++;
} else if (j<((M_X_MAX>>3)-1) && pt1[1] == m2) {
pt4 = pt1-1; /* Initialize repeats */
m1 = 3;
++j;
++pt1;
if (pt3 < pt4) { /* flush literals */
*pt2++ = pt4-pt3-1;
for (;pt3 < pt4;)
*pt2++ = *pt3++;
}
}
pt1++;
} else {
if (m1) { /* End of run, how many? */
--m1;
*pt2++ = -m1;
*pt2++ = m2;
pt3 = pt1;
pt4 = 0;
m1 = 0;
}
m2 = *pt1++; /* set prev char */
}
}
/* Dump end of line */
if (m1) { /* finish repeats */
--m1;
*pt2++ = -m1;
*pt2++ = m2;
} else if (pt3 < pt1) { /* finish literals */
*pt2++ = pt1-pt3-1;
for(;pt3 < pt1;)
*pt2++ = *pt3++;
}
Fwrite(fd, pt2 - pbuf, pbuf);
}
#else
/* Dump it straight, no repeat-suppression */
c = (M_X_MAX>>3)-1;
for (i=0; i<M_Y_MAX; i++) {
Fwrite(fd, 1, &c);
Fwrite(fd, c+1, pt1);
pt1 += c+1;
}
#endif
Fclose(fd);
}
Supexec(remover);
}