home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fred Fish Collection 1.5
/
ffcollection-1-5-1992-11.iso
/
ff_disks
/
500-599
/
ff589.lza
/
Term
/
TermSrc.lha
/
SaveILBM.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-10-03
|
13KB
|
610 lines
/* $Revision Header * Header built automatically - do not edit! *************
*
* (C) Copyright 1985-1991 by Jim Kent & Olaf `Olsen' Barthel
*
* Name .....: SaveILBM.c
* Created ..: Monday 21-Jan-91 20:12
* Revision .: 0
*
* Date Author Comment
* ========= ======== ====================
* 21-Jan-91 Olsen Modified this file!
*
* $Revision Header ********************************************************/
#include "TermGlobal.h"
/* This is basically Jim Kent's IFF-ILBM writer. Changes I made:
*
* - Put all support files into a single file.
* - Added iffparse.library function calls.
* - Added the CAMG chunk and implemented 32 bit viewmode IDs.
* - Wrote a small routine to save the data.
* - Added the ANNO version chunk.
* - Changed the way the original source code was indented and
* the names of some variables.
*/
/* A bitmap header. */
struct BitMapHeader
{
UWORD w, h; /* raster width & height in pixels */
UWORD x, y; /* position for this image */
UBYTE nPlanes; /* # source bitplanes */
UBYTE masking; /* masking technique */
UBYTE compression; /* compression algoithm */
UBYTE pad1; /* UNUSED. For consistency, put 0 here.*/
UWORD transparentColor; /* transparent "color number" */
UBYTE xAspect, yAspect; /* aspect ratio, a rational number x/y */
WORD pageWidth, pageHeight; /* source "page" size in pixels */
};
/* Compression status. */
#define DUMP 0
#define RUN 1
/* Run length encoding constants. */
#define MINRUN 3
#define MAXRUN 128
#define MAXDAT 128
/* Size of the IFF write cache. */
#define IFF_SIZE 4096
/* Cache and cache index. */
STATIC UBYTE IFFBuffer[IFF_SIZE];
STATIC WORD IFFSize;
/* FlushIFF(struct IFFHandle *IFFHandle):
*
* Flush the contents of the IFF write cache.
*/
STATIC BYTE
FlushIFF(struct IFFHandle *IFFHandle)
{
if(IFFSize)
{
if(WriteChunkBytes(IFFHandle,IFFBuffer,IFFSize) != IFFSize)
{
IFFSize = 0;
return(FALSE);
}
IFFSize = 0;
}
return(TRUE);
}
/* PutIFF(struct IFFHandle *IFFHandle,UBYTE c):
*
* Send a single byte to the IFF write cache.
*/
STATIC BYTE
PutIFF(struct IFFHandle *IFFHandle,UBYTE c)
{
if(IFFSize == IFF_SIZE)
if(!FlushIFF(IFFHandle))
return(FALSE);
IFFBuffer[IFFSize++] = c;
return(TRUE);
}
/* WriteIFF(struct IFFHandle *IFFHandle,UBYTE *Data,WORD Size):
*
* Write a buffer to the IFF cache.
*/
STATIC BYTE
WriteIFF(struct IFFHandle *IFFHandle,UBYTE *Data,LONG Size)
{
LONG Len;
while(Size)
{
if(IFFSize == IFF_SIZE)
if(!FlushIFF(IFFHandle))
return(FALSE);
if((Len = Size) > IFF_SIZE - IFFSize)
Len = IFF_SIZE - IFFSize;
CopyMem(&Data[0],&IFFBuffer[IFFSize],Len);
IFFSize += Len;
Size -= Len;
Data = &Data[Len];
}
return(TRUE);
}
STATIC LONG
PackRow(struct IFFHandle *FileHandle,UBYTE *Source,LONG Size)
{
UBYTE c,LastByte = 0;
BYTE CompMode = DUMP;
WORD InBuf = 1; /* number of chars in buffer */
WORD RunStart = 0; /* buffer index current run starts */
LONG PutSize = 0;
UBYTE LineBuf[MAXDAT * 3 / 2]; /* I think MAXDAT+1 would suffice */
LineBuf[0] = LastByte = *Source++; /* so have valid LastByte */
Size--; /* since one byte eaten. */
for( ; Size ; --Size)
{
LineBuf[InBuf++] = c = *Source++;
switch(CompMode)
{
case DUMP: /* If the buffer is full, write the length byte, then the data */
if(InBuf > MAXDAT)
{
if(!PutIFF(FileHandle,InBuf-2))
return(FALSE);
if(!WriteIFF(FileHandle,LineBuf,InBuf-1))
return(0);
PutSize += InBuf;
LineBuf[0] = c;
InBuf = 1;
RunStart = 0;
break;
}
if(c == LastByte)
{
if(InBuf - RunStart >= MINRUN)
{
if(RunStart > 0)
{
if(!PutIFF(FileHandle,RunStart-1))
return(FALSE);
if(!WriteIFF(FileHandle,LineBuf,RunStart))
return(0);
PutSize += RunStart+1;
}
CompMode = RUN;
}
else
{
if(!RunStart)
CompMode = RUN;
}
/* no dump in progress, so can't lose by making
these 2 a run. */
}
else
RunStart = InBuf - 1;/* first of run */
break;
case RUN: if((c != LastByte) ||(InBuf - RunStart > MAXRUN))
{
/* output run */
if(!PutIFF(FileHandle,-(InBuf - RunStart - 2)))
return(FALSE);
if(!PutIFF(FileHandle,LastByte))
return(FALSE);
PutSize += 2;
LineBuf[0] = c;
InBuf = 1;
RunStart = 0;
CompMode = DUMP;
}
break;
}
LastByte = c;
}
switch(CompMode)
{
case DUMP: if(!PutIFF(FileHandle,InBuf-1))
return(FALSE);
if(!WriteIFF(FileHandle,LineBuf,InBuf))
return(FALSE);
PutSize += InBuf+1;
break;
case RUN: if(!PutIFF(FileHandle,-(InBuf - RunStart - 1)))
return(FALSE);
if(!PutIFF(FileHandle,LastByte))
return(FALSE);
PutSize += 2;
break;
}
return(PutSize);
}
STATIC LONG
PackBitMap(struct IFFHandle *FileHandle,struct BitMap *BitMap,LONG Height)
{
LONG i,j,RowLength,CompressedLength = 0,PlaneOffset = 0;
for(i = 0 ; i < Height ; i++)
{
for(j = 0 ; j < BitMap -> Depth ; j++)
{
if(!(RowLength = PackRow(FileHandle,BitMap -> Planes[j] + PlaneOffset,BitMap -> BytesPerRow)))
return(0);
CompressedLength += RowLength;
}
PlaneOffset += BitMap -> BytesPerRow;
}
return(CompressedLength);
}
STATIC BYTE
WriteILBM(UBYTE *FileName,UBYTE *Colours,struct BitMap *BitMap,LONG OffsetX,BYTE OffsetY,LONG Width,LONG Height,LONG Compressed,LONG PageWidth,LONG PageHeight,ULONG ViewModes)
{
struct IFFHandle *FileHandle;
struct BitMapHeader BitMapHeader;
LONG RowOffset;
LONG i,j;
WORD NumColours = 32;
BYTE Success = TRUE;
if(BitMap)
{
if((NumColours = 1 << BitMap -> Depth) > 32)
NumColours = 32;
if(ViewModes & HAM)
NumColours = 16;
}
if(FileHandle = AllocIFF())
{
if(FileHandle -> iff_Stream = Open(FileName,MODE_NEWFILE))
{
InitIFFasDOS(FileHandle);
if(!OpenIFF(FileHandle,IFFF_WRITE))
{
/* say its a FORM ILBM */
if(!PushChunk(FileHandle,'ILBM','FORM',IFFSIZE_UNKNOWN))
{
/* initialize the BitMapHeader to normal values */
BitMapHeader . masking = 0;
BitMapHeader . pad1 = 0;
BitMapHeader . transparentColor = 0;
if(Compressed)
BitMapHeader . compression = 1;
else
BitMapHeader . compression = 0;
BitMapHeader . pageWidth = PageWidth;
BitMapHeader . pageHeight = PageHeight;
BitMapHeader . yAspect = 11;
/* mask out all unwanted bits. */
ViewModes &= ~(SPRITES | VP_HIDE | GENLOCK_AUDIO | GENLOCK_VIDEO);
if((ViewModes & HIRES) && (ViewModes & LACE))
BitMapHeader . xAspect = 10;
if(!(ViewModes & HIRES) && (ViewModes & LACE))
BitMapHeader . xAspect = 20;
if((ViewModes & HIRES) && !(ViewModes & LACE))
BitMapHeader . xAspect = 5;
if(!(ViewModes & HIRES) && !(ViewModes & LACE))
BitMapHeader . xAspect = 10;
/* if it's not just a color map give the dimensions of rasters */
if(BitMap)
{
BitMapHeader . w = Width;
BitMapHeader . h = Height;
BitMapHeader . nPlanes = BitMap -> Depth;
BitMapHeader . x = OffsetX;
BitMapHeader . y = OffsetY;
}
if(!PushChunk(FileHandle,0,'BMHD',IFFSIZE_UNKNOWN))
{
if(WriteChunkBytes(FileHandle,&BitMapHeader,sizeof(BitMapHeader)) == sizeof(BitMapHeader))
{
if(!PopChunk(FileHandle))
{
if(!PushChunk(FileHandle,0,'ANNO',IFFSIZE_UNKNOWN))
{
extern UBYTE VersTag[];
if(WriteChunkBytes(FileHandle,&VersTag[1],strlen(&VersTag[1])) != strlen(&VersTag[1]))
Success = FALSE;
if(PopChunk(FileHandle))
Success = FALSE;
}
if(Success && !PushChunk(FileHandle,0,'CMAP',IFFSIZE_UNKNOWN))
{
if(WriteChunkBytes(FileHandle,Colours,3 * NumColours) == 3 * NumColours)
{
if(!PopChunk(FileHandle))
{
if(!PushChunk(FileHandle,0,'CAMG',IFFSIZE_UNKNOWN))
{
if(WriteChunkBytes(FileHandle,&ViewModes,sizeof(ULONG)) == sizeof(ULONG))
{
if(!PopChunk(FileHandle))
{
if(!PushChunk(FileHandle,0,'BODY',IFFSIZE_UNKNOWN))
{
if(Compressed)
{
if(!PackBitMap(FileHandle,BitMap,Height))
Success = FALSE;
else
{
if(!FlushIFF(FileHandle))
Success = FALSE;
}
}
else
{
i = Height;
RowOffset = 0;
while(--i >= 0 && Success)
{
for(j = 0 ; j < BitMap -> Depth ; j++)
{
if(WriteChunkBytes(FileHandle,BitMap -> Planes[j] + RowOffset,Height) != Height)
{
Success = FALSE;
break;
}
RowOffset += BitMap -> BytesPerRow;
}
}
}
if(PopChunk(FileHandle))
Success = FALSE;
}
else
Success = FALSE;
}
else
Success = FALSE;
}
else
Success = FALSE;
}
else
Success = FALSE;
}
else
Success = FALSE;
}
else
Success = FALSE;
}
else
Success = FALSE;
}
else
Success = FALSE;
}
else
Success = FALSE;
}
else
Success = FALSE;
if(PopChunk(FileHandle))
Success = FALSE;
}
else
Success = FALSE;
}
else
Success = FALSE;
Close(FileHandle -> iff_Stream);
}
else
Success = FALSE;
FreeIFF(FileHandle);
}
else
Success = FALSE;
return(Success);
}
/* SaveRPort():
*
* Save the contents of a given RastPort to an IFF-ILBM
* file, use iffparse.library to get the job done.
*/
LONG
SaveRPort(struct RastPort *RPort,struct ViewPort *VPort,LONG LeftEdge,LONG TopEdge,LONG Width,LONG Height,LONG ParentWidth,LONG ParentHeight,LONG Cookie,STRPTR Name)
{
UBYTE ColTable[32 * 3];
struct BitMap DstMap,*SMap = RPort -> BitMap;
LONG IFF_Result,i,r,g,b;
LONG PacketDims[4];
BYTE ClosedWindow = FALSE;
/* It is impossible to drag the packet window to
* a place where it doesn't overlap the main window.
* To avoid unpleasant effects we'll close it
* and reopen it after saving the main window
* contents.
*/
if(PacketWindow)
{
PacketDims[0] = PacketWindow -> LeftEdge;
PacketDims[1] = PacketWindow -> TopEdge;
PacketDims[2] = PacketWindow -> Width;
PacketDims[3] = PacketWindow -> Height;
PacketWindow -> Flags |= WFLG_RMBTRAP;
ClearMenuStrip(PacketWindow);
CloseWindow(PacketWindow);
PacketWindow = NULL;
ClosedWindow = TRUE;
}
/* Reset buffer counter. */
IFFSize = 0;
/* Perform `cookie cut'? */
if(LeftEdge || TopEdge || Cookie)
{
Cookie = TRUE;
memset(&DstMap,0,sizeof(struct BitMap));
InitBitMap(&DstMap,SMap -> Depth,Width,Height);
for(i = 0 ; i < SMap -> Depth ; i++)
{
if(!(DstMap . Planes[i] = (PLANEPTR)AllocVec(DstMap . BytesPerRow * DstMap . Rows,MEMF_CHIP | MEMF_CLEAR)))
{
IFF_Result = FALSE;
goto Stop;
}
}
BltBitMap(SMap,LeftEdge,TopEdge,&DstMap,0,0,Width,Height,0xC0,0xFF,NULL);
SMap = &DstMap;
}
/* Convert the colours. */
for(i = 0 ; i < 32 ; i++)
{
UWORD TmpCol = GetRGB4(VPort -> ColorMap,i);
r = (TmpCol >> 8) & 0xF;
g = (TmpCol >> 4) & 0xF;
b = (TmpCol ) & 0xF;
ColTable[i * 3 + 0] = r << 4;
ColTable[i * 3 + 1] = g << 4;
ColTable[i * 3 + 2] = b << 4;
}
/* Write the IFF-ILBM file. */
IFF_Result = WriteILBM(Name,ColTable,SMap,LeftEdge,TopEdge,Width,Height,TRUE,ParentWidth,ParentHeight,GetVPModeID(VPort));
/* Free the display cookie. */
Stop: if(Cookie)
{
for(i = 0 ; i < DstMap . Depth ; i++)
{
if(DstMap . Planes[i])
FreeVec(DstMap . Planes[i]);
}
}
/* Delete truncated file or set the `not executable' bit
* if successful.
*/
if(!IFF_Result)
DeleteFile(Name);
else
SetProtection(Name,FIBF_EXECUTE);
/* Be a good boy and reopen the packet window. */
if(ClosedWindow)
{
if(PacketWindow = OpenWindowTags(NULL,
WA_Left, PacketDims[0],
WA_Top, PacketDims[1],
WA_Width, PacketDims[2],
WA_Height, PacketDims[3],
WA_Activate, TRUE,
WA_DragBar, TRUE,
WA_DepthGadget, TRUE,
WA_CloseGadget, TRUE,
WA_RMBTrap, TRUE,
WA_SizeGadget, TRUE,
WA_MinWidth, 80,
WA_MinHeight, 27,
WA_MaxWidth, Screen -> Width,
WA_MaxHeight, 27,
WA_CustomScreen,Screen,
WA_IDCMP, STRINGIDCMP | IDCMP_CLOSEWINDOW | IDCMP_MENUPICK | IDCMP_ACTIVEWINDOW | IDCMP_RAWKEY,
WA_Title, "Packet Window",
TAG_DONE))
{
AddGList(PacketWindow,PacketGadgetList,(UWORD)-1,(UWORD)-1,NULL);
RefreshGList(PacketGadgetList,PacketWindow,NULL,(UWORD)-1);
GT_RefreshWindow(PacketWindow,NULL);
SetMenuStrip(PacketWindow,PacketMenu);
PacketWindow -> Flags &= ~WFLG_RMBTRAP;
}
else
DeletePacketWindow();
}
return(IFF_Result);
}