imagiff.cpp

来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 800 行 · 第 1/2 页

CPP
800
字号
/////////////////////////////////////////////////////////////////////////////
// Name:        imagiff.h
// Purpose:     wxImage handler for Amiga IFF images
// Author:      Steffen Gutmann, Thomas Meyer
// RCS-ID:      $Id: imagiff.cpp,v 1.12 2004/11/10 21:02:24 VZ Exp $
// Copyright:   (c) Steffen Gutmann, 2002
// Licence:     wxWindows licence
/////////////////////////////////////////////////////////////////////////////

// Parts of this source are based on the iff loading algorithm found
// in xviff.c.  Permission by the original author, Thomas Meyer, and
// by the author of xv, John Bradley for using the iff loading part
// in wxWidgets has been gratefully given.

#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
#pragma implementation "imagiff.h"
#endif

// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
#  pragma hdrstop
#endif

#ifndef WX_PRECOMP
#  include "wx/defs.h"
#endif

#if wxUSE_IMAGE && wxUSE_IFF

#include "wx/imagiff.h"
#include "wx/wfstream.h"
#include "wx/log.h"
#include "wx/intl.h"

#if wxUSE_PALETTE
    #include "wx/palette.h"
#endif // wxUSE_PALETTE

#include <stdlib.h>
#include <string.h>


// --------------------------------------------------------------------------
// Constants
// --------------------------------------------------------------------------

// Error codes:
//  Note that the error code wxIFF_TRUNCATED means that the image itself
//  is most probably OK, but the decoder didn't reach the end of the data
//  stream; this means that if it was not reading directly from file,
//  the stream will not be correctly positioned.
//

enum
{
    wxIFF_OK = 0,                   /* everything was OK */
    wxIFF_INVFORMAT,                /* error in iff header */
    wxIFF_MEMERR,                   /* error allocating memory */
    wxIFF_TRUNCATED                 /* file appears to be truncated */
};

// --------------------------------------------------------------------------
// wxIFFDecoder class
// --------------------------------------------------------------------------

// internal class for storing IFF image data
class IFFImage
{
public:
    unsigned int w;                 /* width */
    unsigned int h;                 /* height */
    int transparent;                /* transparent color (-1 = none) */
    int colors;                     /* number of colors */
    unsigned char *p;               /* bitmap */
    unsigned char *pal;             /* palette */

    IFFImage() : w(0), h(0), colors(0), p(0), pal(0) {}
    ~IFFImage() { delete [] p; delete [] pal; }
};

class WXDLLEXPORT wxIFFDecoder
{
private:
    IFFImage *m_image;        // image data
    wxInputStream *m_f;       // input stream
    unsigned char *databuf;
    unsigned char *picptr;
    unsigned char *decomp_mem;

    void Destroy();

public:
    // get data of current frame
    unsigned char* GetData() const;
    unsigned char* GetPalette() const;
    int GetNumColors() const;
    unsigned int GetWidth() const;
    unsigned int GetHeight() const;
    int GetTransparentColour() const;

    // constructor, destructor, etc.
    wxIFFDecoder(wxInputStream *s);
    ~wxIFFDecoder() { Destroy(); }
    bool CanRead();
    int ReadIFF();
    bool ConvertToImage(wxImage *image) const;
};


//---------------------------------------------------------------------------
// wxIFFDecoder constructor and destructor
//---------------------------------------------------------------------------

wxIFFDecoder::wxIFFDecoder(wxInputStream *s)
{
    m_f = s;
    m_image = 0;
    databuf = 0;
    decomp_mem = 0;
}

void wxIFFDecoder::Destroy()
{
    delete m_image;
    m_image = 0;
    delete [] databuf;
    databuf = 0;
    delete [] decomp_mem;
    decomp_mem = 0;
}

//---------------------------------------------------------------------------
// Convert this image to a wxImage object
//---------------------------------------------------------------------------

// This function was designed by Vaclav Slavik

bool wxIFFDecoder::ConvertToImage(wxImage *image) const
{
    // just in case...
    image->Destroy();

    // create the image
    image->Create(GetWidth(), GetHeight());

    if (!image->Ok())
        return false;

    unsigned char *pal = GetPalette();
    unsigned char *src = GetData();
    unsigned char *dst = image->GetData();
    int colors = GetNumColors();
    int transparent = GetTransparentColour();
    long i;

    // set transparent colour mask
    if (transparent != -1)
    {
        for (i = 0; i < colors; i++)
        {
            if ((pal[3 * i + 0] == 255) &&
                (pal[3 * i + 1] == 0) &&
                (pal[3 * i + 2] == 255))
            {
                pal[3 * i + 2] = 254;
            }
        }

        pal[3 * transparent + 0] = 255,
        pal[3 * transparent + 1] = 0,
        pal[3 * transparent + 2] = 255;

        image->SetMaskColour(255, 0, 255);
    }
    else
        image->SetMask(false);

#if wxUSE_PALETTE
    if (pal && colors > 0)
    {
        unsigned char* r = new unsigned char[colors];
        unsigned char* g = new unsigned char[colors];
        unsigned char* b = new unsigned char[colors];

        for (i = 0; i < colors; i++)
        {
            r[i] = pal[3*i + 0];
            g[i] = pal[3*i + 1];
            b[i] = pal[3*i + 2];
        }

        image->SetPalette(wxPalette(colors, r, g, b));

        delete [] r;
        delete [] g;
        delete [] b;
    }
#endif // wxUSE_PALETTE

    // copy image data
    for (i = 0; i < (long)(GetWidth() * GetHeight()); i++, src += 3, dst += 3)
    {
    dst[0] = src[0];
    dst[1] = src[1];
    dst[2] = src[2];
    }

    return true;
}


//---------------------------------------------------------------------------
// Data accessors
//---------------------------------------------------------------------------

// Get data for current frame

unsigned char* wxIFFDecoder::GetData() const    { return (m_image->p); }
unsigned char* wxIFFDecoder::GetPalette() const { return (m_image->pal); }
int wxIFFDecoder::GetNumColors() const          { return m_image->colors; }
unsigned int wxIFFDecoder::GetWidth() const     { return (m_image->w); }
unsigned int wxIFFDecoder::GetHeight() const    { return (m_image->h); }
int wxIFFDecoder::GetTransparentColour() const { return m_image->transparent; }

//---------------------------------------------------------------------------
// IFF reading and decoding
//---------------------------------------------------------------------------

//
// CanRead:
//  Returns true if the file looks like a valid IFF, false otherwise.
//
bool wxIFFDecoder::CanRead()
{
    unsigned char buf[12];

    if ( !m_f->Read(buf, WXSIZEOF(buf)) )
        return false;

    m_f->SeekI(-(wxFileOffset)WXSIZEOF(buf), wxFromCurrent);

    return (memcmp(buf, "FORM", 4) == 0) && (memcmp(buf+8, "ILBM", 4) == 0);
}


// ReadIFF:
// Based on xv source code by Thomas Meyer
// Permission for use in wxWidgets has been gratefully given.

typedef unsigned char byte;
#define IFFDEBUG 0

/*************************************************************************
  void decomprle(source, destination, source length, buffer size)

  Decompress run-length encoded data from source to destination. Terminates
  when source is decoded completely or destination buffer is full.

  The decruncher is as optimized as I could make it, without risking
  safety in case of corrupt BODY chunks.
**************************************************************************/

static void decomprle(const byte *sptr, byte *dptr, long slen, long dlen)
{
    byte codeByte, dataByte;

    while ((slen > 0) && (dlen > 0)) {
    // read control byte
    codeByte = *sptr++;

    if (codeByte < 0x80) {
        codeByte++;
        if ((slen > (long) codeByte) && (dlen >= (long) codeByte)) {
        slen -= codeByte + 1;
        dlen -= codeByte;
        while (codeByte > 0) {
            *dptr++ = *sptr++;
            codeByte--;
        }
        }
        else slen = 0;
    }

    else if (codeByte > 0x80) {
        codeByte = 0x81 - (codeByte & 0x7f);
        if ((slen > (long) 0) && (dlen >= (long) codeByte)) {
        dataByte = *sptr++;
        slen -= 2;
        dlen -= codeByte;
        while (codeByte > 0) {
            *dptr++ = dataByte;
            codeByte--;
        }
        }
        else slen = 0;
    }
    }
}

/******************************************/
static unsigned int iff_getword(const byte *ptr)
{
    unsigned int v;

    v = *ptr++;
    v = (v << 8) + *ptr;
    return v;
}

/******************************************/
static unsigned long iff_getlong(const byte *ptr)
{
    unsigned long l;

    l = *ptr++;
    l = (l << 8) + *ptr++;
    l = (l << 8) + *ptr++;
    l = (l << 8) + *ptr;
    return l;
}

// Define internal ILBM types
#define ILBM_NORMAL     0
#define ILBM_EHB        1
#define ILBM_HAM        2
#define ILBM_HAM8       3
#define ILBM_24BIT      4

int wxIFFDecoder::ReadIFF()
{
    Destroy();

    m_image = new IFFImage();
    if (m_image == 0) {
    Destroy();
    return wxIFF_MEMERR;
    }

    // compute file length
    wxFileOffset currentPos = m_f->TellI();
    m_f->SeekI(0, wxFromEnd);
    long filesize = m_f->TellI();
    m_f->SeekI(currentPos, wxFromStart);

    // allocate memory for complete file
    if ((databuf = new byte[filesize]) == 0) {
    Destroy();
    return wxIFF_MEMERR;
    }

    m_f->Read(databuf, filesize);
    const byte *dataend = databuf + filesize;

    // initialize work pointer. used to trace the buffer for IFF chunks
    const byte *dataptr = databuf;

    // check for minmal size
    if (dataptr + 12 > dataend) {
    Destroy();
    return wxIFF_INVFORMAT;
    }

    // check if we really got an IFF file
    if (strncmp((char *)dataptr, "FORM", 4) != 0) {
    Destroy();
    return wxIFF_INVFORMAT;
    }

    dataptr = dataptr + 8;                  // skip ID and length of FORM

    // check if the IFF file is an ILBM (picture) file
    if (strncmp((char *) dataptr, "ILBM", 4) != 0) {
    Destroy();
    return wxIFF_INVFORMAT;
    }

    wxLogTrace(_T("iff"), _T("IFF ILBM file recognized"));

    dataptr = dataptr + 4;                                // skip ID

    //
    // main decoding loop. searches IFF chunks and handles them.
    // terminates when BODY chunk was found or dataptr ran over end of file
    //
    bool BMHDok = false, CMAPok = false, CAMGok = false;
    int bmhd_width = 0, bmhd_height = 0, bmhd_bitplanes = 0, bmhd_transcol = -1;
    byte bmhd_masking = 0, bmhd_compression = 0;
    long camg_viewmode = 0;
    int colors = 0;
    while (dataptr + 8 <= dataend) {
    // get chunk length and make even
    size_t chunkLen = (iff_getlong(dataptr + 4) + 1) & 0xfffffffe;
#ifdef __VMS
       // Silence compiler warning
       int chunkLen_;
       chunkLen_ = chunkLen;
       if (chunkLen_ < 0) {     // format error?
#else

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?