/* Copyright 1990 by Christopher A. Wichura. See file GIFMachine.doc for full description of rights. */ #include "GIFMachine.h" #include #include #include #include #include extern struct GIFdescriptor gdesc; EXTERNBITPLANE; extern struct MinList CommentList; extern char *AbortMsg; extern UWORD *SHAMmem; BYTE *PlaneBuf; BOOL Laced; UBYTE *Planes[8]; static UBYTE CompBuf[256]; static ULONG PlanePos; /* our version number stuff */ extern ULONG __far Version; extern ULONG __far Revision; BOOL WriteIFF(char *tofile, BOOL DeepFlag) { register struct IFFHandle *iff; register int index; register ULONG ChunkSize; register UWORD current; char WrittenBy[40]; ColorRegister ColourBuf; PutStr("...Writing IFF file."); if (!(iff = AllocIFF())) { PutStr("\n......Error allocating IFF handle.\n"); return TRUE; } if (!(iff->iff_Stream = Open(tofile, MODE_NEWFILE))) { MyPrintf("\n......Error %ld trying to create %s.", IoErr(), tofile); goto EndWriteIFF; } InitIFFasDOS(iff); if (OpenIFF(iff, IFFF_WRITE)) { PutStr("\n......Error writing to IFF.\n"); goto EndWriteIFF; } if (PushChunk(iff, ID_ILBM, FORM, IFFSIZE_UNKNOWN)) { PutStr("\n......Error writing to IFF.\n"); goto EndWriteIFF; } if (PushChunk(iff, 0L, MakeID('A','N','N','O'), IFFSIZE_UNKNOWN)) { PutStr("\n......Error writing to IFF.\n"); goto EndWriteIFF; } MySPrintf(WrittenBy, "Written by GIFMachine v%ld.%ld on ", Version, Revision); if (WriteChunkBytes(iff, (APTR)&WrittenBy, strlen(WrittenBy)) != strlen(WrittenBy)) { PutStr("\n......Error writing to IFF.\n"); goto EndWriteIFF; } { struct DateTime dat; char Date[LEN_DATSTRING + 1]; int DateLength; DateStamp((LONG *)&dat.dat_Stamp); dat.dat_Format = FORMAT_DOS; dat.dat_Flags = 0; dat.dat_StrDay = NULL; dat.dat_StrDate = Date; dat.dat_StrTime = NULL; memset(Date, 0, LEN_DATSTRING + 1); DateToStr(&dat); DateLength = strlen(Date) + 1; if (WriteChunkBytes(iff, (APTR)&Date, DateLength) != DateLength) { PutStr("\n......Error writing to IFF.\n"); goto EndWriteIFF; } } if (PopChunk(iff)) { PutStr("\n......Error writing to IFF.\n"); goto EndWriteIFF; } { struct CommentNode *cn; char ANNObuf[1]; #define C_BLOCK_ID "GIF Comment Block: " ANNObuf[0] = 0; while (cn = (struct CommentNode *)RemHead((struct List *)&CommentList)) { if (PushChunk(iff, 0L, MakeID('A','N','N','O'), IFFSIZE_UNKNOWN)) { PutStr("\n......Error writing to IFF.\n"); goto EndWriteIFF; } if (WriteChunkBytes(iff, (APTR)C_BLOCK_ID, strlen(C_BLOCK_ID)) != strlen(C_BLOCK_ID)) { PutStr("\n......Error writing to IFF.\n"); goto EndWriteIFF; } if (WriteChunkBytes(iff, (APTR)cn->cn_Comment, cn->cn_CommentLength) != cn->cn_CommentLength) { PutStr("\n......Error writing to IFF.\n"); goto EndWriteIFF; } if (WriteChunkBytes(iff, (APTR)ANNObuf, 1) != 1) { PutStr("\n......Error writing to IFF.\n"); goto EndWriteIFF; } if (PopChunk(iff)) { PutStr("\n......Error writing to IFF.\n"); goto EndWriteIFF; } } } if (PushChunk(iff, 0L, ID_BMHD, sizeof(BitMapHeader))) { PutStr("\n......Error writing to IFF.\n"); goto EndWriteIFF; } { BitMapHeader bmh; bmh.w = gdesc.gd_Width & ~1L; /* make sure width is even */ bmh.h = gdesc.gd_Height; bmh.x = bmh.y = 0; bmh.nPlanes = (DeepFlag ? 24 : 6); bmh.masking = mskNone; bmh.compression = cmpByteRun1; bmh.pad1 = 0; bmh.transparentColor = 0; bmh.xAspect = (Laced ? x320x400Aspect : x320x200Aspect); bmh.yAspect = (Laced ? y320x400Aspect : y320x200Aspect); bmh.pageWidth = 320; bmh.pageHeight = (Laced ? 400 : 200); if (WriteChunkBytes(iff, (APTR)&bmh, sizeof(BitMapHeader)) != sizeof(BitMapHeader)) { PutStr("\n......Error writing to IFF.\n"); goto EndWriteIFF; } } if (PopChunk(iff)) { PutStr("\n......Error writing to IFF.\n"); goto EndWriteIFF; } if (PushChunk(iff, 0L, ID_CAMG, 4)) { PutStr("\n......Error writing to IFF.\n"); goto EndWriteIFF; } { LONG CAMGbuf[1]; CAMGbuf[0] = (DeepFlag ? 0 : HAM) | (Laced ? LACE : 0); if (WriteChunkBytes(iff, (APTR)&CAMGbuf, 4) != 4) { PutStr("\n......Error writing to IFF.\n"); goto EndWriteIFF; } } if (PopChunk(iff)) { PutStr("\n......Error writing to IFF.\n"); goto EndWriteIFF; } if (!DeepFlag) { if (PushChunk(iff, 0L, ID_CMAP, 16 * 3)) { PutStr("\n......Error writing to IFF.\n"); goto EndWriteIFF; } for (index = 0; index < 16; index++) { current = SHAMmem[index]; ColourBuf.red = (current >> 4) & 0xF0; ColourBuf.green = current & 0xF0; ColourBuf.blue = (current & 15) << 4; if (WriteChunkBytes(iff, (APTR)&ColourBuf, sizeofColorRegister) != sizeofColorRegister) { PutStr("\n......Error writing to IFF.\n"); goto EndWriteIFF; } } if (PopChunk(iff)) { PutStr("\n......Error writing to IFF.\n"); goto EndWriteIFF; } ChunkSize = (Laced ? gdesc.gd_Height / 2 : gdesc.gd_Height) * 16 * sizeof(UWORD); if (PushChunk(iff, 0L, MakeID('S','H','A','M'), ChunkSize + 2)) { PutStr("\n......Error writing to IFF.\n"); goto EndWriteIFF; } { UWORD SHAMversion[1]; SHAMversion[0] = 0; if (WriteChunkBytes(iff, (APTR)&SHAMversion, sizeof(UWORD)) != sizeof(UWORD)) { PutStr("\n......Error writing to IFF.\n"); goto EndWriteIFF; } } if (WriteChunkBytes(iff, (APTR)SHAMmem, ChunkSize) != ChunkSize) { PutStr("\n......Error writing to IFF.\n"); goto EndWriteIFF; } if (PopChunk(iff)) { PutStr("\n......Error writing to IFF.\n"); goto EndWriteIFF; } } /* end if (!DeepFlag) */ if (PushChunk(iff, 0L, ID_BODY, IFFSIZE_UNKNOWN)) { PutStr("\n......Error writing to IFF.\n"); goto EndWriteIFF; } /* now we actually write the body chunk out */ { register int plane; register int col; register UWORD x; register UWORD y; register int index; UBYTE PlaneMask, ColMask; UWORD Cols; PutStr("\n......Line "); Cols = (gdesc.gd_Width + 7) / 8; if (IS_ODD(Cols)) Cols++; for (y = 0; y < gdesc.gd_Height; y++) { MyPrintf("%5ld", y); if (SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { MyPrintf("\n%s", AbortMsg); CloseIFF(iff); Close(iff->iff_Stream); FreeIFF(iff); MyExit(ABORTEXITVAL); } for (index = 0; index < (DeepFlag ? 3 : 1); index++) { col = 0; ColMask = 1L << 7; for (x = 0; x < gdesc.gd_Width; x++) { if (DeepFlag) current = *((UBYTE *)&BitPlane[y][x]+index); else current = GetValue(x, y); PlaneMask = 1; for (plane = 0; plane < (DeepFlag ? 8 : 6); plane++) { if (current & PlaneMask) Planes[plane][col] |= ColMask; PlaneMask <<= 1; } if (ColMask == 1) { ColMask = 1L << 7; col++; } else ColMask >>= 1; } /* now we need to compress the scan line */ { register BOOL state; register char c; register char lastc; register UWORD nbuf; register UWORD rstart; for (plane = 0; plane < (DeepFlag ? 8 : 6); plane++) { CompBuf[0] = lastc = c = Planes[plane][0]; state = FALSE; PlanePos = rstart = 0; nbuf = col = 1; while (col < Cols) { CompBuf[nbuf++] = c = Planes[plane][col++]; switch (state) { case FALSE: if (nbuf > 128) { OutDump(nbuf - 1); CompBuf[0] = c; nbuf = 1; rstart = 0; break; } if (c == lastc) { if (nbuf - rstart >= 3) { if (rstart > 0) OutDump(rstart); state = TRUE; } else if (rstart == 0) state = TRUE; } else rstart = nbuf - 1; break; case TRUE: if ((c != lastc) || (nbuf - rstart > 128)) { OutRun(nbuf - 1 - rstart, lastc); CompBuf[0] = c; nbuf = 1; rstart = 0; state = FALSE; } break; } lastc = c; } switch (state) { case FALSE: OutDump(nbuf); break; case TRUE: OutRun(nbuf - rstart, lastc); break; } /* now write the compressed plane out */ if (WriteChunkBytes(iff, (APTR)PlaneBuf, PlanePos) != PlanePos) { PutStr("\n......Error writing to IFF.\n"); goto EndWriteIFF; } memset((char *)Planes[plane], 0, Cols); } } } MyPrintf("\x9B" "5D"); } } if (PopChunk(iff)) { PutStr("\n......Error writing to IFF.\n"); goto EndWriteIFF; } if (PopChunk(iff)) { PutStr("\n......Error writing to IFF.\n"); goto EndWriteIFF; } PutStr("\x9B" "5D\x9BKWritten.\n"); EndWriteIFF: CloseIFF(iff); if (iff->iff_Stream) Close(iff->iff_Stream); FreeIFF(iff); return TRUE; } void OutDump(int nn) { register int index; PlaneBuf[PlanePos++] = nn - 1; for (index = 0; index < nn; index++) PlaneBuf[PlanePos++] = CompBuf[index]; } void OutRun(int nn, int cc) { PlaneBuf[PlanePos++] = -(nn - 1); PlaneBuf[PlanePos++] = cc; }