/** routine for saveing an IFF picture to the clipboard... By Stephen Vermeulen 1989. **/ struct IOClipReq clipboardIO = 0; struct MsgPort clipboardMsgPort = 0; struct MsgPort satisfyMsgPort = 0; #ifndef MakeID #define MakeID(a, b, c, d)\ ( ((long) (a)<<24) + ((long) (b)<<16) + ((long)(c)<<8) + (long)(d) ) #endif short CBisOpen; /** this will be set to 1 when the clipboard has been successfully opened. **/ /** the following two routines are from a CBM example somewhere on the Fish Disks... **/ int CBOpen(unit) int unit; { int error; /* open the clipboard device */ if ((error = OpenDevice("clipboard.device", (long) unit, &clipboardIO, 0L)) != 0) CBisOpen = 0; /* Set up the message port in the I/O request */ clipboardMsgPort.mp_Node.ln_Type = NT_MSGPORT; clipboardMsgPort.mp_Flags = 0; clipboardMsgPort.mp_SigBit = AllocSignal(-1L); clipboardMsgPort.mp_SigTask = (struct Task *) FindTask((char *) NULL); AddPort(&clipboardMsgPort); clipboardIO.io_Message.mn_ReplyPort = &clipboardMsgPort; satisfyMsgPort.mp_Node.ln_Type = NT_MSGPORT; satisfyMsgPort.mp_Flags = 0; satisfyMsgPort.mp_SigBit = AllocSignal(-1L); satisfyMsgPort.mp_SigTask = (struct Task *) FindTask((char *) NULL); AddPort(&satisfyMsgPort); CBisOpen = 1; } CBClose() { if (CBisOpen) { if (clipboardMsgPort.mp_SigBit > 0) FreeSignal(clipboardMsgPort.mp_SigBit); if (satisfyMsgPort.mp_SigBit > 0) FreeSignal(satisfyMsgPort.mp_SigBit); RemPort(&satisfyMsgPort); RemPort(&clipboardMsgPort); CloseDevice(&clipboardIO); CBisOpen = 0; } } /** the rest of the clipboard routines are my own work **/ /** this is used to set the mode of the clipboard, to either read or write (0 or 1) **/ CBSetMode(mode) int mode; { if (mode) /** write **/ { clipboardIO.io_Command = CMD_WRITE; clipboardIO.io_Offset = 0; clipboardIO.io_ClipID = 0; } else { clipboardIO.io_Command = CMD_READ; clipboardIO.io_Offset = 0; clipboardIO.io_ClipID = 0; } } /** the following is the function that replaces fread(), calling the clipboard instead. **/ gfread(data, length, n) UBYTE *data; int length, n; { if (CBisOpen) { while (n) { clipboardIO.io_Command = CMD_READ; clipboardIO.io_Data = (STRPTR) data; clipboardIO.io_Length = length; DoIO(&clipboardIO); data += length; --n; } } } gputc(c) char c; { if (CBisOpen) { clipboardIO.io_Command = CMD_WRITE; clipboardIO.io_Data = (STRPTR) &c; clipboardIO.io_Length = 1; DoIO(&clipboardIO); } } gfwrite(data, length, n) UBYTE *data; int length, n; { if (CBisOpen) { while (n) { clipboardIO.io_Command = CMD_WRITE; clipboardIO.io_Data = (STRPTR) data; clipboardIO.io_Length = length; DoIO(&clipboardIO); data += length; --n; } } } CBEndSession(mode) int mode; { if (!CBisOpen) return; if (mode) /** end of writing **/ { clipboardIO.io_Command = CMD_UPDATE; DoIO(&clipboardIO); } else /** end of reading **/ { clipboardIO.io_Command = CMD_READ; clipboardIO.io_Offset = 2000000000; /** don't use -1L here! the clipboard treats this as a SIGNED quantity! **/ clipboardIO.io_Length = 1; clipboardIO.io_Data = (STRPTR) 0; DoIO(&clipboardIO); } } /** note the following does not support seeking relative to the end of the clip... **/ gfseek(offset, origin) long offset; int origin; { if (CBisOpen) { switch (origin) { case 0: /** rel to begining **/ clipboardIO.io_Offset = offset; break; case 1: /** rel to current pos **/ clipboardIO.io_Offset += offset; break; } } } long gftell() { if (CBisOpen) { return(clipboardIO.io_Offset); } else return(NULL); } gfopen(mode) char *mode; { if (mode[0] == 'r') CBSetMode(0); else CBSetMode(1); } gfclose(mode) char *mode; { if (mode[0] == 'r') { /** we must force a read beyond the end of the file to tell clipboard we are done with it! **/ CBEndSession(0); } else CBEndSession(1); } #define MaxPackedSize(rowSize) ( (rowSize) + ( ((rowSize) + 127) >> 7) ) #define RowBytes(w) ((((w) + 15) >> 4) << 1) /************************************************************ The following are the IFF read and write routines ************************************************************/ #define FORM MakeID('F', 'O', 'R', 'M') #define ILBM MakeID('I', 'L', 'B', 'M') #define BMHD MakeID('B', 'M', 'H', 'D') #define BODY MakeID('B', 'O', 'D', 'Y') #define VDFL MakeID('V', 'D', 'F', 'L') #define CMAP MakeID('C', 'M', 'A', 'P') #define GRAB MakeID('G', 'R', 'A', 'B') #define CAMG MakeID('C', 'A', 'M', 'G') #define CRNG MakeID('C', 'R', 'N', 'G') struct BMHdr { USHORT w, h; SHORT x, y; UBYTE nPlanes, masking, compression, pad1; USHORT transparentColor; UBYTE xAspect, yAspect; SHORT pageWidth, pageHeight; }; struct PictHdr { LONG IFFid, filelen, ILBMid, BMHDid, BMHDsize; struct BMHdr bmhdr; }; char comp_buf[1036]; /* buffer to hold the compressed input data */ short comp_buf_len; /* number of bytes in the compressed buffer */ /*************************************************************** Quicky little routine that just writes a long word to the file ****************************************************************/ void write_WORD(i) LONG i; { (void) gfwrite( (char *) &i, 4, 1); } void write_CMAP(s, d) struct Screen *s; short d; { short i, colour; if (d == 6) d == 5; /* cause of ehb */ write_WORD(CMAP); write_WORD(3L * (1L << d)); for (i = 0; i < (1 << d); ++i) { colour = GetRGB4(s->ViewPort.ColorMap, (long) i); gputc((colour & 0x0f00) >> 4); /****** red ******/ gputc((colour & 0x00f0)); /***** green *****/ gputc((colour & 0x000f) << 4); /****** blue *****/ } } /************************************************************ The following routine is used by the IFF saving routines to write the body section of the image. Returns true if sucessful, else it returns FALSE. ************************************************************/ int save_BODY(bm, comp) struct BitMap *bm; short comp; { short y, nbytes, bwidth, depth; short p; struct BitMap mybm; char *source, *dest, *bp; nbytes = bwidth = bm->BytesPerRow; mybm = *bm; depth = bm->Depth; /******************* scan down the rows ********************/ for (y = 0; y < bm->Rows; ++y) { /************************** Sweep down the bit planes ***************************/ for (p = 0; p < depth; ++p) { bp = (char *) mybm.Planes[p]; if (comp) { /**************** pack this row *****************/ source = bp; dest = &comp_buf[0]; nbytes = PackRow(&source, &dest, bwidth); bp = &comp_buf[0]; } /************************ Now write out the data *************************/ gfwrite((char *) bp, nbytes, 1); mybm.Planes[p] += bwidth; } /* end for bitplanes */ } /* end for rows */ return(1); } /************************************************************ The routine to save designated area of a raster port in IFF format. ************************************************************/ short save_bm(bm, s) struct BitMap *bm; struct Screen *s; { LONG vmode, body_start, body_len, file_len; struct PictHdr Pict; short i; FILE *out; char *name; CBOpen(0); if (!CBisOpen) return(0); gfopen("w"); Pict.bmhdr.w = bm->BytesPerRow << 3; Pict.bmhdr.h = bm->Rows; Pict.bmhdr.x = 0; Pict.bmhdr.y = 0; Pict.bmhdr.nPlanes = bm->Depth; Pict.bmhdr.masking = 0; Pict.bmhdr.compression = 1; Pict.bmhdr.pad1 = 0; Pict.bmhdr.transparentColor = 0; Pict.bmhdr.xAspect = (s->Width > 400) ? 10 : 20; Pict.bmhdr.yAspect = (s->Height > 280) ? 11 : 22; Pict.bmhdr.pageWidth = s->Width; Pict.bmhdr.pageHeight = s->Height; Pict.IFFid = FORM; Pict.filelen = 0; /* fill in later */ Pict.ILBMid = ILBM; Pict.BMHDid = BMHD; Pict.BMHDsize = sizeof(struct BMHdr); gfwrite( (char *) &Pict, (short) sizeof(struct PictHdr), 1); write_CMAP(s, bm->Depth); vmode = s->ViewPort.Modes; vmode &= HIRES | LACE | EXTRA_HALFBRITE | HAM; write_WORD(CAMG, out); write_WORD(4L, out); write_WORD(vmode, out); /********************* Write the BODY chunk **********************/ write_WORD(BODY); write_WORD(0L); /* fill in later */ body_start = gftell(); save_BODY(bm, 1); body_len = gftell() - body_start; /* length of body chunk */ if (gftell() & 0x01L) gputc(0); /* pad byte if needed */ file_len = gftell(); /************************** Reposition in the file and write the actual body and file lengths. ***************************/ gfseek(body_start - 4L, 0); /* body length */ write_WORD(body_len); gfseek(4L, 0); /* file length */ write_WORD(file_len - 8L); gfclose("w"); CBClose(); return(1); }