home *** CD-ROM | disk | FTP | other *** search
/ Amiga Elysian Archive / AmigaElysianArchive.iso / comm / term23_2.lha / Source_Code / termSource / termSaveILBM.c < prev    next >
C/C++ Source or Header  |  1992-08-18  |  12KB  |  580 lines

  1. /*
  2. **    $Id: termSaveILBM.c,v 1.3 92/08/18 16:13:02 olsen Sta Locker: olsen $
  3. **    $Revision: 1.3 $
  4. **    $Date: 92/08/18 16:13:02 $
  5. **
  6. **    Support routines for saving IFF-ILBM files
  7. **
  8. **    Copyright © 1985-1992 by Jim Kent & Olaf `Olsen' Barthel
  9. */
  10.  
  11. #include "termGlobal.h"
  12.  
  13.     /* This is basically Jim Kent's IFF-ILBM writer. Changes I made:
  14.      *
  15.      * - Put all support files into a single file.
  16.      * - Added iffparse.library function calls.
  17.      * - Added the CAMG chunk and implemented 32 bit viewmode IDs.
  18.      * - Wrote a small routine to save the data.
  19.      * - Added the ANNO version chunk.
  20.      * - Added pixel aspect calculation routines.
  21.      * - Changed the way the original source code was indented and
  22.      *   the names of some variables.
  23.      */
  24.  
  25.     /* A bitmap header. */
  26.  
  27. struct BitMapHeader
  28. {
  29.     UWORD    w,h;            /* raster width & height in pixels */
  30.     UWORD    x,y;            /* position for this image */
  31.     UBYTE    nPlanes;        /* # source bitplanes */
  32.     UBYTE    masking;        /* masking technique */
  33.     UBYTE    compression;        /* compression algoithm */
  34.     UBYTE    pad1;            /* UNUSED.  For consistency, put 0 here.*/
  35.     UWORD    transparentColor;    /* transparent "color number" */
  36.     UBYTE    xAspect,yAspect;    /* aspect ratio, a rational number x/y */
  37.     WORD    pageWidth,pageHeight;    /* source "page" size in pixels */
  38. };
  39.  
  40.     /* Compression status. */
  41.  
  42. #define DUMP    0
  43. #define RUN    1
  44.  
  45.     /* Run length encoding constants. */
  46.  
  47. #define MINRUN    3
  48. #define MAXRUN    128
  49. #define MAXDAT    128
  50.  
  51.     /* Size of the IFF write cache. */
  52.  
  53. #define IFF_SIZE    4096
  54.  
  55.     /* Cache and cache index. */
  56.  
  57. STATIC UBYTE    IFFBuffer[IFF_SIZE];
  58. STATIC WORD    IFFSize;
  59.  
  60.     /* FlushIFF(struct IFFHandle *IFFHandle):
  61.      *
  62.      *    Flush the contents of the IFF write cache.
  63.      */
  64.  
  65. STATIC BYTE
  66. FlushIFF(struct IFFHandle *IFFHandle)
  67. {
  68.     if(IFFSize)
  69.     {
  70.         if(WriteChunkBytes(IFFHandle,IFFBuffer,IFFSize) != IFFSize)
  71.         {
  72.             IFFSize = 0;
  73.             return(FALSE);
  74.         }
  75.  
  76.         IFFSize = 0;
  77.     }
  78.  
  79.     return(TRUE);
  80. }
  81.  
  82.     /* PutIFF(struct IFFHandle *IFFHandle,UBYTE c):
  83.      *
  84.      *    Send a single byte to the IFF write cache.
  85.      */
  86.  
  87. STATIC BYTE
  88. PutIFF(struct IFFHandle *IFFHandle,UBYTE c)
  89. {
  90.     if(IFFSize == IFF_SIZE)
  91.         if(!FlushIFF(IFFHandle))
  92.             return(FALSE);
  93.  
  94.     IFFBuffer[IFFSize++] = c;
  95.  
  96.     return(TRUE);
  97. }
  98.  
  99.     /* WriteIFF(struct IFFHandle *IFFHandle,UBYTE *Data,WORD Size):
  100.      *
  101.      *    Write a buffer to the IFF cache.
  102.      */
  103.  
  104. STATIC BYTE
  105. WriteIFF(struct IFFHandle *IFFHandle,UBYTE *Data,LONG Size)
  106. {
  107.     LONG Len;
  108.  
  109.     while(Size)
  110.     {
  111.         if(IFFSize == IFF_SIZE)
  112.             if(!FlushIFF(IFFHandle))
  113.                 return(FALSE);
  114.  
  115.         if((Len = Size) > IFF_SIZE - IFFSize)
  116.             Len = IFF_SIZE - IFFSize;
  117.  
  118.         CopyMem(&Data[0],&IFFBuffer[IFFSize],Len);
  119.  
  120.         IFFSize    += Len;
  121.         Size    -= Len;
  122.  
  123.         Data = &Data[Len];
  124.     }
  125.  
  126.     return(TRUE);
  127. }
  128.  
  129. STATIC LONG
  130. PackRow(struct IFFHandle *FileHandle,UBYTE *Source,LONG Size)
  131. {
  132.     UBYTE    c,LastByte    = 0;
  133.     BYTE    CompMode    = DUMP;
  134.     WORD    InBuf        = 1;        /* number of chars in buffer */
  135.     WORD    RunStart    = 0;        /* buffer index current run starts */
  136.     LONG    PutSize        = 0;
  137.  
  138.     UBYTE    LineBuf[MAXDAT * 3 / 2];    /* I think MAXDAT+1 would suffice */
  139.  
  140.     LineBuf[0] = LastByte = *Source++;    /* so have valid LastByte */
  141.     Size--;                    /* since one byte eaten. */
  142.  
  143.     for( ; Size ; --Size)
  144.     {
  145.         LineBuf[InBuf++] = c = *Source++;
  146.  
  147.         switch(CompMode)
  148.         {
  149.             case DUMP:    /* If the buffer is full, write the length byte, then the data */
  150.  
  151.                     if(InBuf > MAXDAT)
  152.                     {
  153.                         if(!PutIFF(FileHandle,InBuf-2))
  154.                             return(FALSE);
  155.  
  156.                         if(!WriteIFF(FileHandle,LineBuf,InBuf-1))
  157.                             return(0);
  158.  
  159.                         PutSize += InBuf;
  160.  
  161.                         LineBuf[0]    = c;
  162.                         InBuf        = 1;
  163.                         RunStart    = 0;
  164.  
  165.                         break;
  166.                     }
  167.  
  168.                     if(c == LastByte)
  169.                     {
  170.                         if(InBuf - RunStart >= MINRUN)
  171.                         {
  172.                             if(RunStart > 0)
  173.                             {
  174.                                 if(!PutIFF(FileHandle,RunStart-1))
  175.                                     return(FALSE);
  176.  
  177.                                 if(!WriteIFF(FileHandle,LineBuf,RunStart))
  178.                                     return(0);
  179.  
  180.                                 PutSize += RunStart+1;
  181.                             }
  182.  
  183.                             CompMode = RUN;
  184.                         }
  185.                         else
  186.                         {
  187.                             if(!RunStart)
  188.                                 CompMode = RUN;
  189.                         }
  190.  
  191.                             /* no dump in progress, so can't lose by making
  192.                                these 2 a run. */
  193.                     }
  194.                     else
  195.                         RunStart = InBuf - 1;/* first of run */
  196.  
  197.                     break;
  198.  
  199.             case RUN:    if((c != LastByte) ||(InBuf - RunStart > MAXRUN))
  200.                     {
  201.                         /* output run */
  202.  
  203.                         if(!PutIFF(FileHandle,-(InBuf - RunStart - 2)))
  204.                             return(FALSE);
  205.  
  206.                         if(!PutIFF(FileHandle,LastByte))
  207.                             return(FALSE);
  208.  
  209.                         PutSize += 2;
  210.  
  211.                         LineBuf[0]    = c;
  212.                         InBuf        = 1;
  213.                         RunStart    = 0;
  214.                         CompMode    = DUMP;
  215.                     }
  216.  
  217.                     break;
  218.         }
  219.  
  220.         LastByte = c;
  221.     }
  222.  
  223.     switch(CompMode)
  224.     {
  225.         case DUMP:    if(!PutIFF(FileHandle,InBuf-1))
  226.                     return(FALSE);
  227.  
  228.                 if(!WriteIFF(FileHandle,LineBuf,InBuf))
  229.                     return(FALSE);
  230.  
  231.                 PutSize += InBuf+1;
  232.                 break;
  233.  
  234.         case RUN:    if(!PutIFF(FileHandle,-(InBuf - RunStart - 1)))
  235.                     return(FALSE);
  236.  
  237.                 if(!PutIFF(FileHandle,LastByte))
  238.                     return(FALSE);
  239.  
  240.                 PutSize += 2;
  241.                 break;
  242.     }
  243.  
  244.     return(PutSize);
  245. }
  246.  
  247. STATIC LONG
  248. PackBitMap(struct IFFHandle *FileHandle,struct BitMap *BitMap,LONG Height)
  249. {
  250.     LONG i,j,RowLength,CompressedLength = 0,PlaneOffset = 0;
  251.  
  252.     for(i = 0 ; i < Height ; i++)
  253.     {
  254.         for(j = 0 ; j < BitMap -> Depth ; j++)
  255.         {
  256.             if(!(RowLength = PackRow(FileHandle,BitMap -> Planes[j] + PlaneOffset,BitMap -> BytesPerRow)))
  257.                 return(0);
  258.  
  259.             CompressedLength += RowLength;
  260.         }
  261.  
  262.         PlaneOffset += BitMap -> BytesPerRow;
  263.     }
  264.  
  265.     return(CompressedLength);
  266. }
  267.  
  268. STATIC BYTE
  269. WriteILBM(UBYTE *FileName,UBYTE *Colours,struct BitMap *BitMap,LONG OffsetX,BYTE OffsetY,LONG Width,LONG Height,LONG Compressed,LONG PageWidth,LONG PageHeight,ULONG ViewModes)
  270. {
  271.     struct IFFHandle    *FileHandle;
  272.     struct BitMapHeader     BitMapHeader;
  273.     LONG             RowOffset;
  274.     LONG             i,j;
  275.     WORD             NumColours = 32;
  276.     struct DisplayInfo     DI;
  277.     BYTE             Success = TRUE;
  278.  
  279.         /* Calculate number of colours available. */
  280.  
  281.     if(BitMap)
  282.     {
  283.         if((NumColours = 1 << BitMap -> Depth) > 32)
  284.             NumColours = 32;
  285.  
  286.         if(ViewModes & HAM)
  287.             NumColours = 16;
  288.     }
  289.  
  290.     if(FileHandle = AllocIFF())
  291.     {
  292.         if(FileHandle -> iff_Stream = Open(FileName,MODE_NEWFILE))
  293.         {
  294.             InitIFFasDOS(FileHandle);
  295.  
  296.             if(!OpenIFF(FileHandle,IFFF_WRITE))
  297.             {
  298.                     /* Say its a FORM ILBM */
  299.  
  300.                 if(!PushChunk(FileHandle,'ILBM','FORM',IFFSIZE_UNKNOWN))
  301.                 {
  302.                         /* Initialize the BitMapHeader to normal values */
  303.  
  304.                     BitMapHeader . masking        = 0;
  305.                     BitMapHeader . pad1        = 0;
  306.                     BitMapHeader . transparentColor    = 0;
  307.  
  308.                     if(Compressed)
  309.                         BitMapHeader . compression = 1;
  310.                     else
  311.                         BitMapHeader . compression = 0;
  312.  
  313.                     BitMapHeader . pageWidth    = PageWidth;
  314.                     BitMapHeader . pageHeight    = PageHeight;
  315.  
  316.                         /* Mask out all unwanted bits. */
  317.  
  318.                     ViewModes &= ~(SPRITES | VP_HIDE | GENLOCK_AUDIO | GENLOCK_VIDEO);
  319.  
  320.                         /* Determine pixel aspect. */
  321.  
  322.                     if(GetDisplayInfoData(NULL,(APTR)&DI,sizeof(struct DisplayInfo),DTAG_DISP,ViewModes))
  323.                     {
  324.                         BitMapHeader . xAspect = DI . Resolution . x;
  325.                         BitMapHeader . yAspect = DI . Resolution . y;
  326.                     }
  327.                     else
  328.                     {
  329.                         BitMapHeader . xAspect = 44;
  330.                         BitMapHeader . yAspect = (GfxBase -> DisplayFlags & PAL) ? 44 : 52;
  331.  
  332.                         if(ViewModes & HIRES)
  333.                             BitMapHeader . xAspect >>= 1;
  334.  
  335.                         if(ViewModes & LACE)
  336.                             BitMapHeader . yAspect >>= 1;
  337.                     }
  338.  
  339.                         /* If it's not just a color map give the dimensions of rasters */
  340.  
  341.                     if(BitMap)
  342.                     {
  343.                         BitMapHeader . w    = Width;
  344.                         BitMapHeader . h    = Height;
  345.                         BitMapHeader . nPlanes    = BitMap -> Depth;
  346.                         BitMapHeader . x    = OffsetX;
  347.                         BitMapHeader . y    = OffsetY;
  348.                     }
  349.  
  350.                     if(!PushChunk(FileHandle,0,'BMHD',sizeof(struct BitMapHeader)))
  351.                     {
  352.                         if(WriteChunkBytes(FileHandle,&BitMapHeader,sizeof(BitMapHeader)) == sizeof(BitMapHeader))
  353.                         {
  354.                             if(!PopChunk(FileHandle))
  355.                             {
  356.                                 if(!PushChunk(FileHandle,0,'ANNO',IFFSIZE_UNKNOWN))
  357.                                 {
  358.                                     extern UBYTE VersTag[];
  359.  
  360.                                     if(WriteChunkBytes(FileHandle,&VersTag[1],strlen(&VersTag[1])) != strlen(&VersTag[1]))
  361.                                         Success = FALSE;
  362.  
  363.                                     if(PopChunk(FileHandle))
  364.                                         Success = FALSE;
  365.                                 }
  366.  
  367.                                 if(Success && !PushChunk(FileHandle,0,'CMAP',3 * NumColours))
  368.                                 {
  369.                                     if(WriteChunkBytes(FileHandle,Colours,3 * NumColours) == 3 * NumColours)
  370.                                     {
  371.                                         if(!PopChunk(FileHandle))
  372.                                         {
  373.                                             if(!PushChunk(FileHandle,0,'CAMG',sizeof(ULONG)))
  374.                                             {
  375.                                                 if(WriteChunkBytes(FileHandle,&ViewModes,sizeof(ULONG)) == sizeof(ULONG))
  376.                                                 {
  377.                                                     if(!PopChunk(FileHandle))
  378.                                                     {
  379.                                                         if(!PushChunk(FileHandle,0,'BODY',IFFSIZE_UNKNOWN))
  380.                                                         {
  381.                                                             if(Compressed)
  382.                                                             {
  383.                                                                 if(!PackBitMap(FileHandle,BitMap,Height))
  384.                                                                     Success = FALSE;
  385.                                                                 else
  386.                                                                 {
  387.                                                                     if(!FlushIFF(FileHandle))
  388.                                                                         Success = FALSE;
  389.                                                                 }
  390.                                                             }
  391.                                                             else
  392.                                                             {
  393.                                                                 i = Height;
  394.                                                                 RowOffset = 0;
  395.  
  396.                                                                 while(--i >= 0 && Success)
  397.                                                                 {
  398.                                                                     for(j = 0 ; j < BitMap -> Depth ; j++)
  399.                                                                     {
  400.                                                                         if(WriteChunkBytes(FileHandle,BitMap -> Planes[j] + RowOffset,Height) != Height)
  401.                                                                         {
  402.                                                                             Success = FALSE;
  403.                                                                             break;
  404.                                                                         }
  405.  
  406.                                                                         RowOffset += BitMap -> BytesPerRow;
  407.                                                                     }
  408.                                                                 }
  409.                                                             }
  410.  
  411.                                                             if(PopChunk(FileHandle))
  412.                                                                 Success = FALSE;
  413.                                                         }
  414.                                                         else
  415.                                                             Success = FALSE;
  416.                                                     }
  417.                                                     else
  418.                                                         Success = FALSE;
  419.                                                 }
  420.                                                 else
  421.                                                     Success = FALSE;
  422.                                             }
  423.                                             else
  424.                                                 Success = FALSE;
  425.                                         }
  426.                                         else
  427.                                             Success = FALSE;
  428.                                     }
  429.                                     else
  430.                                         Success = FALSE;
  431.                                 }
  432.                                 else
  433.                                     Success = FALSE;
  434.                             }
  435.                             else
  436.                                 Success = FALSE;
  437.                         }
  438.                         else
  439.                             Success = FALSE;
  440.                     }
  441.                     else
  442.                         Success = FALSE;
  443.  
  444.                     if(PopChunk(FileHandle))
  445.                         Success = FALSE;
  446.                 }
  447.                 else
  448.                     Success = FALSE;
  449.             }
  450.             else
  451.                 Success = FALSE;
  452.  
  453.             Close(FileHandle -> iff_Stream);
  454.         }
  455.         else
  456.             Success = FALSE;
  457.  
  458.         FreeIFF(FileHandle);
  459.     }
  460.     else
  461.         Success = FALSE;
  462.  
  463.     return(Success);
  464. }
  465.  
  466.     /* SaveRPort():
  467.      *
  468.      *    Save the contents of a given RastPort to an IFF-ILBM
  469.      *    file, use iffparse.library to get the job done.
  470.      */
  471.  
  472. LONG
  473. SaveRPort(struct RastPort *RPort,struct ViewPort *VPort,LONG LeftEdge,LONG TopEdge,LONG Width,LONG Height,LONG ParentWidth,LONG ParentHeight,LONG Cookie,STRPTR Name)
  474. {
  475.     UBYTE         ColTable[32 * 3];
  476.  
  477.     struct BitMap     DstMap,
  478.             *SMap = RPort -> BitMap;
  479.  
  480.     LONG         IFF_Result,
  481.              r,g,b,
  482.              i;
  483.  
  484.     UWORD         TmpCol;
  485.  
  486.     BYTE         ClosedWindow = FALSE;
  487.  
  488.         /* It is impossible to drag the packet window to
  489.          * a place where it doesn't overlap the main window.
  490.          * To avoid unpleasant effects we'll close it
  491.          * and reopen it after saving the main window
  492.          * contents.
  493.          */
  494.  
  495.     if(PacketWindow)
  496.     {
  497.         ClosedWindow = TRUE;
  498.  
  499.         DeletePacketWindow(TRUE);
  500.     }
  501.  
  502.         /* Reset buffer counter. */
  503.  
  504.     IFFSize = 0;
  505.  
  506.         /* Perform `cookie cut' (Note: in order to use the standard
  507.          * IFF-ILBM save routines, we will use the cookie cut if a
  508.          * interleaved screen bitmap is present).
  509.          */
  510.  
  511.     if(LeftEdge || TopEdge || Cookie || InterleavedBitMap)
  512.     {
  513.         Cookie = TRUE;
  514.  
  515.         memset(&DstMap,0,sizeof(struct BitMap));
  516.  
  517.         InitBitMap(&DstMap,SMap -> Depth,Width,Height);
  518.  
  519.         for(i = 0 ; i < SMap -> Depth ; i++)
  520.         {
  521.             if(!(DstMap . Planes[i] = AllocRaster(Width,Height)))
  522.             {
  523.                 IFF_Result = FALSE;
  524.  
  525.                 goto Stop;
  526.             }
  527.         }
  528.  
  529.         BltBitMap(SMap,LeftEdge,TopEdge,&DstMap,0,0,Width,Height,0xC0,0xFF,NULL);
  530.  
  531.         SMap = &DstMap;
  532.     }
  533.  
  534.         /* Convert the colours. */
  535.  
  536.     for(i = 0 ; i < 32 ; i++)
  537.     {
  538.         TmpCol = GetRGB4(VPort -> ColorMap,i)
  539.  
  540.         r = (TmpCol >> 8) & 0xF;
  541.         g = (TmpCol >> 4) & 0xF;
  542.         b = (TmpCol     ) & 0xF;
  543.  
  544.         ColTable[i * 3 + 0] = (r << 4) | r;
  545.         ColTable[i * 3 + 1] = (g << 4) | g;
  546.         ColTable[i * 3 + 2] = (b << 4) | b;
  547.     }
  548.  
  549.         /* Write the IFF-ILBM file. */
  550.  
  551.     IFF_Result = WriteILBM(Name,ColTable,SMap,LeftEdge,TopEdge,Width,Height,TRUE,ParentWidth,ParentHeight,GetVPModeID(VPort));
  552.  
  553.         /* Free the display cookie. */
  554.  
  555. Stop:    if(Cookie)
  556.     {
  557.         for(i = 0 ; i < DstMap . Depth ; i++)
  558.         {
  559.             if(DstMap . Planes[i])
  560.                 FreeRaster(DstMap . Planes[i],Width,Height);
  561.         }
  562.     }
  563.  
  564.         /* Delete truncated file or set the `not executable' bit
  565.          * if successful.
  566.          */
  567.  
  568.     if(!IFF_Result)
  569.         DeleteFile(Name);
  570.     else
  571.         SetProtection(Name,FIBF_EXECUTE);
  572.  
  573.         /* Be a good boy and reopen the packet window. */
  574.  
  575.     if(ClosedWindow)
  576.         CreatePacketWindow();
  577.  
  578.     return(IFF_Result);
  579. }
  580.